наследование — C ++: законно ли объявлять метод виртуальным в производном классе, если он не был виртуальным в базе?

Базовый класс специально объявляет метод не виртуальным.
Он работает в 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. Почему это работает?

1

Решение

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"!
6

Другие решения

Это законно. Метод становится 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 потому что метод вызывается динамически.

2

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

0
По вопросам рекламы [email protected]