Является ли ключевое слово "virtual" необязательным в базовых классах в C ++? - PullRequest
3 голосов
/ 28 августа 2011

Я пытаюсь понять функцию ключевого слова "virtual" в C ++ - рассмотрим этот пример:

#ifdef USE_VIRTUAL
struct a {
  virtual void say_hi() { std::cout << "hello from a" << std::endl; }
};
#else
struct a {
  void say_hi() { std::cout << "hello from a" << std::endl; }
};
#endif

struct b : public a {
  void say_hi() { std::cout << "hello from b" << std::endl; }
};

int main( int argc, char** argc )
{
  a a_obj;
  b b_obj;
  a_obj.say_hi();
  b_obj.say_hi();
}

Эта программа выводит:

hello from a
hello from b

независимо от того, объявлен ли :: say_hi как виртуальный или нет. Поскольку функция корректно переопределяется, даже если say_hi не объявлен виртуальным, тогда какова функция объявления его как виртуального?

1 Ответ

6 голосов
/ 28 августа 2011

Вы не используете полиморфизм. Полиморфное поведение влияет только на указатели и ссылки на базовые классы, например:

class A; class B1 : A; class B2 : A;

B1 x;
B2 y;
A  z;

A & a1 = x;  // static type A&, dynamic type B1&
A & a2 = y;  // static type A&, dynamic type B2&
A & a3 = z;  // static and dynamic type A&

Теперь доступ к функциям-членам a1, a2, a3 подвержен полиморфизму и виртуальной диспетчеризации.

Однако , вы должны объявить первую функцию наверху виртуальной иерархии наследования, т.е. в A! В вашем примере без virtual полиморфизм отсутствует, и вы всегда вызываете функцию-член соответствующего статического типа объекта. Чтобы проверить это, добавьте еще несколько строк:

a & bref = b_obj;
bref.say_hi();       // call b::say_hi() if virtual, a::say_hi if not
bref.a::say_hi();    // always call a::say_hi()
...