Чистая виртуальная функция с реализацией

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

class A {
public:
    virtual void f() = 0;
};

void A::f() {
    cout<<"Test"<<endl;
}

Код выше OK?

Какова цель сделать его чистой виртуальной функцией с реализацией?

Ответ 1

Чистая функция virtual должна быть реализована в производном типе, который будет непосредственно создан, однако базовый тип все еще может определить реализацию. Производный класс может явным образом вызвать реализацию базового класса (если разрешают разрешения доступа), используя имя с полным расширением (путем вызова A::f() в вашем примере - если A::f() было public или protected)). Что-то вроде:

class B : public A {

    virtual void f() {
        // class B doesn't have anything special to do for f()
        //  so we'll call A's

        // note that A declaration of f() would have to be public 
        //  or protected to avoid a compile time problem

        A::f();
    }

};

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

Обратите внимание, что даже если это разрешено языком, это не то, что я вижу обычно используемым (и тот факт, что это может быть сделано, кажется, удивляет большинство программистов на C++, даже опытных).

Ответ 2

Чтобы быть ясным, вы не понимаете, что = 0; после использования виртуальной функции.

= 0 означает, что производные классы должны обеспечивать реализацию, а не то, что базовый класс не может обеспечить реализацию.

На практике, когда вы отмечаете виртуальную функцию как pure (= 0), в определении определения очень мало смысла, потому что он никогда не будет вызван, если кто-то явно не делает это через Base:: Function (...) или если конструктор базового класса вызывает эту виртуальную функцию.

Ответ 3

Преимущество этого заключается в том, что он заставляет производные типы по-прежнему переопределять метод, но также обеспечивает реализацию по умолчанию или добавление.

Ответ 4

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

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

Следовательно, одно разумное использование чистых виртуальных функций определяет чистый виртуальный деструктор как ключевое слово "non-final".

Следующий код на удивление правдоподобен:

class Base {
public:
  virtual ~Base() = 0;
};

Base::~Base() {}

class Derived : public Base {};

int main() { 
  // Base b; -- compile error
  Derived d; 
}

Ответ 6

Да, это правильно. В вашем примере классы, которые производятся от A, наследуют интерфейс f() и реализацию по умолчанию. Но вы вынуждаете производные классы реализовывать метод f() (даже если он должен только вызывать реализацию по умолчанию, предоставленную A).

Скотт Майерс обсуждает это в "Эффективном С++" (2-е издание). Пункт № 36. Различия между наследованием интерфейса и наследованием реализации. Номер номера может быть изменен в последнем выпуске.

Ответ 7

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

Чистые тела виртуальных функций в базовом классе полезны, если ваши производные классы хотят вызвать реализацию вашего базового класса.

Ответ 8

"virtual void foo() = 0;" синтаксис не означает, что вы не можете реализовать foo() в текущем классе, вы можете. Это также не означает, что вы должны реализовать его в производных классах. Прежде чем похлопать меня, давайте наблюдать за проблемой алмаза: (Неявный код, заметьте).

class A
{
public: 
    virtual void foo()=0;
    virtual void bar();
}

class B : public virtual A
{
public:
    void foo() { bar(); }
}

class C : public virtual A
{
public:
    void bar();
}

class D : public B, public C
{}

int main(int argc, const char* argv[])
{
    A* obj = new D();
    **obj->foo();**
    return 0;
}

Теперь вызов obj- > foo() приведет к B:: foo(), а затем C:: bar().

Вы видите... чистые виртуальные методы не должны реализовываться в производных классах (foo() не имеет реализации в классе C - компилятор компиляции) В С++ есть много лазеек.

Надеюсь, что смогу помочь: -)