Search code examples
c++inheritancedefinitionvirtual-functionsone-definition-rule

Pure virtual function implementation


I'm reading Scott Meyers' Effective C++ and I'm at the section about inheritance. He said that

Pure virtual functions specify inheritance of interface only.

Simple (impure) virtual functions specify inheritance of interface plus inheritance of a default implementation.

Now, consider the following two classes:

struct A {
    virtual void foo() = 0;
};

void A::foo(){ std::cout << "Default foo" << std::endl; }

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

We still can provide a default implementation for pure virtual functions as I did in the example and call it via qualified-function-call-expression. We can do almost the same for impure virtual functions

struct A {
    virtual void foo(); //No longer pure virtual
};

void A::foo(){ std::cout << "Default foo" << std::endl; }

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

If I don't define the impure virtual function as follows:

struct A {
    virtual void foo();
};



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

it'll work perfectly fine.

DEMO

So, the only purpose of pure virtual functions is to make a class abstract (non-instanciatable)?


Solution

  • A pure virtual function not only makes the base class non-instantiable, but forces all derived classes to implement the corresponding virtual function. If you don't make the base function pure virtual, then the derived classes may choose to not implement it. Defining the pure virtual function is OK, as long as you use it from a derived instance, and it provides an implementation that can be used as default, as Scott Meyers points out.

    Note that your demo doesn't work as you think. If you do what usually is regarding as common when using polymorphism,

    A* p = new B; // or, std::unique_ptr<A> p = make_unique<B>();
    p->foo();
    

    then you get a nasty linker error:

    Undefined symbols for architecture x86_64:

    "typeinfo for A", referenced from: typeinfo for B in ccoVYpAI.o