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, а затем снова получить.