C++ функция переопределения

У меня есть три разных базовых класса:

class BaseA
{
public:
    virtual int foo() = 0;
};

class BaseB
{
public:
    virtual int foo() { return 42; }
};

class BaseC
{
public:
    int foo() { return 42; }
};

Затем я получаю из базы как это (замените X для A, B или C):

class Child : public BaseX
{
public:
    int foo() { return 42; }
};

Как функция переопределяется в трех разных базовых классах? Правильны ли мои три предположения? Есть ли другие оговорки?

  • В BaseA дочерний класс не компилируется, чистая виртуальная функция не определена.
  • В BaseB функция в дочернем случае вызывается при вызове foo на BaseB * или Child *.
  • С BaseC функция в дочернем случае вызывается при вызове foo в Child *, но не на BaseB * (вызывается функция в родительском классе).

Ответы

Ответ 1

В производном классе метод является виртуальным, если он определен виртуальным в базовом классе, даже если ключевое слово virtual не используется в методе производного класса.

  • С BaseA он будет компилироваться и выполняться по назначению, причем foo() является виртуальным и выполняется в классе Child.
  • То же самое с BaseB, он также будет компилироваться и выполняться по назначению, причем foo() является virtual() и выполняется в классе Child.
  • Вместе с BaseC он будет компилироваться и выполняться, но он выполнит версию BaseC, если вы вызовете ее из контекста BaseC и версии Child, если вы вызываете контекст Child.

Ответ 2

Важное правило для запоминания - это когда функция объявлена ​​виртуальной, функции с соответствующими сигнатурами в производных классах всегда являются виртуальными. Таким образом, он переопределяется для Child of A и Child of B, который будет вести себя одинаково (за исключением того, что вы не можете напрямую создавать BaseA).

С C, однако, функция не переопределяется, а перегружается. В этой ситуации имеет значение только статический тип: он будет называть его указателем на (статический тип) вместо того, что действительно является объектом (динамический тип)

Ответ 3

В BaseA дочерний класс не компилировать, чистую виртуальную функцию не определено

Это верно, только если вы попытаетесь создать объект BaseA. Если вы создадите объект Child, а затем вы можете вызвать foo(), используя BaseA * или Child *

С BaseB функция в дочернем вызывается при вызове foo на BaseB * или Ребенок *.

Зависит от типа объекта, поскольку объект может быть либо BaseB, либо Child. Если объект BaseB, то вызывается BaseB:: foo.

С BaseC, функция в ребенке вызывается при вызове foo на Child * но не на BaseB * (функция в родительский класс).

Да, но вы никогда не хотите этого делать.

Ответ 4

С точки зрения полиморфизма предпочитайте A, поэтому вы знаете, что у каждого ребенка есть своя реализация виртуальной функции.
Выберите B в основном, если у вас есть действительная реализация по умолчанию, но тогда вы должны убедиться, что все дочерние классы имеют свою собственную реализацию по мере необходимости. C не является полиморфизмом, поэтому используйте разумно.

Ответ 5

В основном это зависит от того, как вы его назвали.

если вы это сделали:

class Child : public BaseA
{
public:
    int foo() { return 42; }
};

и сделал

BaseA baseA = new Child();
baseA->foo();

Он будет вызывать функцию Child foo.

Однако, если вы это сделали:

BaseA baseA = new BaseA();

Это приведет к ошибке времени компиляции.

Ответ 6

Класс Child будет компилироваться, если он получен из A, вы просто не можете создавать объекты такого типа.

Это может быть полезно, если вы собираетесь переопределить некоторые функции из Base, а затем снова получить.