Вопрос

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

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* (вызывается функция в родительском классе).
Это было полезно?

Решение

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

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

Другие советы

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

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

С Басеей, дочерний класс не компилируется, чистая виртуальная функция не определена

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

С BASEB функция у ребенка вызывается при вызове Foo на BASEB* или Child*.

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

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

Да, но ты никогда не захочешь этого сделать.

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

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

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

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

и сделал

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

Он вызовет функцию foo Чайлда.

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

BaseA baseA = new BaseA();

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top