Разрешает ли C ++ несколько уровней виртуальности? - PullRequest
7 голосов
/ 22 августа 2011

У меня есть базовый класс под названием Object. PhysicsObject наследуется от Object. Ball наследуется от PhysicsObject, а SoftBall наследуется от Ball. Примерно так:

Object
 |
PhysicsObject
 |
Ball
 |
SoftBall

У меня есть метод с именем foo (), который объявлен виртуальным в Object (с учетом реализации, а не чисто виртуальным), затем объявлен и снова реализован как виртуальный в PhysicsObject и Ball. Наконец, SoftBall снова реализует foo (), не объявляя его виртуальным.

Если у меня есть Object *, который указывает на SoftBall, будет ли вызываться версия foo () SoftBall? Если нет, есть ли способ достичь этого эффекта? В основном, этот аспект полиморфизма все еще работает на более чем одном уровне наследования?

Ответы [ 3 ]

8 голосов
/ 22 августа 2011

Если вы объявите виртуальную функцию в базовом классе и объявите функцию с такой же сигнатурой в производном классе, она будет автоматически сделана виртуальной (даже с любым числом уровней классов между).Итак, ответ на ваш вопрос: да, будет вызвана реализация SoftBall foo().

Однако, будьте осторожны, если в сигнатуре есть какая-либо разница, виртуальная функция будет скрыт вместо.Например:

class Object {
public:
  virtual void foo();
};

class InBetween : public Object {
  // assume it has no foo()s
};

class A : public InBetween {
public:
  void foo() const; // DOES NOT OVERRIDE; ((Object *)pA)->foo() calls Object::foo()
                    // However pA->foo() calls this
};

class B: public InBetween {
public:
  void foo() const; // Does not override; pB->foo() calls this if pB is const
  void foo(); // Does override; ((Object *)pB)->foo() calls this. pB->foo() also calls this if pB is non-const
};
6 голосов
/ 22 августа 2011

Если у меня есть Object *, который указывает на SoftBall, будет ли вызываться версия foo () SoftBall? Если нет, есть ли способ достичь этого эффекта? По существу, этот аспект полиморфизма все еще работает на более чем одном уровне наследования?

Да

C ++ определяет методы как виртуальные, если соответствующая перегрузка является виртуальной в базовом классе (в отличие от других языков OO, где переопределения должны быть помечены явно).

http://codepad.org/pL09QWNN


Обратите внимание, что с некоторыми другими ингредиентами вы можете стать действительно прикольными:

#include <iostream>

struct A { virtual void foo() { std::cout << "A::foo();" << std::endl; } };
struct B { virtual void foo() { std::cout << "B::foo();" << std::endl; } };

struct Oa: A, B { using A::foo; };
struct Ob: A, B { using B::foo; };

#define TEST(a) std::cout << #a << ":\t"; a

int main()
{
    A a;
    B b;
    Oa oa;
    Ob ob;

    TEST(a.foo());
    TEST(b.foo());
    TEST(oa.foo());
    TEST(ob.foo());

    std::cout << "But oa through different references:" << std::endl;
    {
        A& ar = oa;
        TEST(ar.foo());

        B& br = oa;
        TEST(br.foo());
    }

    std::cout << "And ob through different references:" << std::endl;
    {
        A& ar = ob;
        TEST(ar.foo());

        B& br = ob;
        TEST(br.foo());
    }

    return 0;
}

Попробуйте предсказать, что будет напечатано здесь. Становится намного веселее, когда вы смешиваете:

  • (изменяемые / постоянные / изменчивые) перегрузки
  • (конфликтующие) аргументы по умолчанию

Я помню, что читал довольно много более и менее ужасных примеров в виде вопроса о пустяках, с которым, я надеюсь, никогда не столкнусь в интервью. Хотя я знаю, что отвечу: «Если у вас есть такой код, я не уверен, что хочу эту работу»?

Вы можете посмотреть на Херба Саттера, Скотта Мейера, и вы будете поражены тем, какие подводные камни скрываются в нашем "C ++ * 1028", так называемом "цивилизованном, милом, маленьком".

1 голос
/ 22 августа 2011

Если у меня есть Object *, который указывает на SoftBall, будет ли вызываться версия foo () SoftBall?Если нет, есть ли способ достичь этого эффекта?В основном, этот аспект полиморфизма все еще работает на более чем одном уровне наследования?

Да.

Конечно, вы могли бы просто попробовать его ...;)


Для потомков вот мой тестовый пример (в котором предполагается, что cout находится в области видимости):

struct Object {
   virtual void foo() {}
};

struct PhysicsObject : Object {};
struct Ball : PhysicsObject {};

struct SoftBall : Ball {
   virtual void foo() {
      cout << "SoftBall";
   }
};

int main() {
   SoftBall sb;
   Object* o = &sb;
   o->foo();
}

// Output: "SoftBall"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...