Базовый класс специально объявляет метод не виртуальным.
Он работает в Visual Studio 2008,2010 и 2012 и все, что использует Ideone компилятор (gcc 4.7+?).
#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 Почему это работает?
Ничто не мешает вам объявить функцию-член в производном классе, имя которого совпадает с именем функции-члена базового класса. Ваша функция в производном классе будет просто скрывать функция базового класса. Между прочим, если функция из производного класса оказывается 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"!
Это законно. Метод становится 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
потому что метод вызывается динамически.
Это законно. Называя функцию в производном классе virtual, вы говорите компилятору во время выполнения проверить метод производного класса на предмет реализации функции перед переходом к базовому классу.