2013-02-26 2 views
1

Базовый класс специально объявляет метод не виртуальным. Работает в Visual Studio 2008,2010 и 2012 и whatever compiler ideone uses (gcc 4.7+?).C++: Можно ли объявить метод виртуальным в производном классе, если он не был виртуальным в базе?

#include <iostream> 

class sayhi 
{ 
public: 
    void hi(){std::cout<<"hello"<<std::endl;} 
}; 

class greet: public sayhi 
{ 
public: 
    virtual void hi(){std::cout<<"hello world"<<std::endl;} 
}; 


int main() 
{ 
    greet noob; 
    noob.hi(); //Prints hello world 
    return 0; 
} 

Это тоже работает - метод является частным и невиртуальном в базовом классе:

#include <iostream> 

class sayhi 
{ 
private: 
    void hi(){std::cout<<"hello"<<std::endl;} 
}; 

class greet: public sayhi 
{ 
public: 
    virtual void hi(){std::cout<<"hello world"<<std::endl;} 
}; 


int main() 
{ 
    greet noob; 
    noob.hi(); //Prints hello world 
    return 0; 
} 

Мои вопросы:

  1. Законно ли это?
  2. Почему это работает?

ответ

6

1. Это законно?

Да.

2. Почему это работает?

Ничто не мешает вам объявить функцию-член в производном классе, который имеет то же имя, что и функция-член базового класса. Ваша функция в производном классе будет просто скрыть функцию базового класса.Между прочим, если функция из производного класса, случается, virtual, то подклассы могут переопределить его:

class howdy : public greet 
{ 
public: 
    // Overrides greet::hi() 
    virtual void hi() { std::cout << "howdy world" << std::endl; } 
}; 

Это, однако, не влияет на sayhi::hi() каким-либо образом: в частности, простое присутствие virtual функции в производном классе, который скрывает его не делает егоvirtual. Таким образом, вы не можете ожидать виртуальной отправки на работу во время вызова функции с помощью указателя или ссылки на экземпляр базы класса sayhi:

sayhi noob; 
noob.hi(); // Will NOT print "hello world"! 

greet gentleman; 
sayhi* p = &gentleman; 
p->hi(); // Will NOT print "hello world"! 

howdy neighbor; 
p = &neighbor; 
p->hi(); // Will NOT print "howdy"! 

greet* pG = &neighbor; 
pG->hi(); // WILL print "howdy"!  
0

Это законно. Назвав функцию в виртуальном производном классе, вы сообщаете компилятору во время выполнения проверить метод производного класса для реализации функции перед переходом в базовый класс.

2

Это законно. Метод становится virtual с этой точки в производных классах greet.

Метод базового класса скрыт (как это произошло бы с virtual).

Вызов метода с помощью указателя greet будет выполнять динамический вызов. Вызов его через sayhi будет решать его статически.

Возьмем, к примеру:

class sayhi 
{ 
public: 
    void hi(){std::cout<<"hello"<<std::endl;} 
}; 

class greet: public sayhi 
{ 
public: 
    virtual void hi(){std::cout<<"hello world"<<std::endl;} 
}; 

class greetuniverse: public greet 
{ 
public: 
    virtual void hi(){std::cout<<"hello universe"<<std::endl;} 
}; 

Следующая

sayhi* p = new greetuniverse; 
p->hi(); 

напечатает hello потому hi не виртуальна в sayhi. Однако

greet* p = new greetuniverse; 
p->hi(); 

напечатает hello universe, так как метод называется динамически.

+0

+1 за правильный ответ и отличный пример – franji1

 Смежные вопросы

  • Нет связанных вопросов^_^