Providing a definition for a pure-virtual function

586 views Asked by At

I'm a Java programmer and was confued about the fact of providing the defintion for pure-virtual functions. In Java I'm used to think about abstract methods as methods we'll provide the deifinitions in a base class. But the following code is perfectly valid:

#include <iostream>

struct A
{
   virtual ~A() = 0;
};

A::~A(){ std::cout << "~A()" << std::endl; }

struct B : A
{
    ~B(){ std::cout << "~B()" << std::endl; }
};

A *a = new B;


int main()
{
    delete a;
}

But if we try to do something like that:

#include <iostream>

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

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

struct B : A
{
    ~B(){ std::cout << "~B()" << std::endl; }
};

A *a = new B;


int main()
{
    delete a;
}

The compiler's going to complaing about providing no definition for pure virtual functions. Why can we define the pure-virtual destructor in a namesapace scope, but can't do that for usual member function.

Is that rather an exception than a rule?

3

There are 3 answers

4
Brian Bi On BEST ANSWER

You are allowed to define any pure virtual member function. However, even though you define A::foo, it is still pure, so A and B are still abstract classes and may not be instantiated. That will be the cause of any errors your compiler may emit.

2
AnT stands with Russia On

You are apparently confused about the reason for the error in the second version of the code.

There's nothing wrong with providing a definition for a pure virtual function, any pure virtual function, in namespace scope. It doesn't matter whether it is a destructor or a regular function. No compiler will ever complain about that.

The definition for A::foo you provided in the second version of the code is perfectly legal and causes no complaints from the compiler. The only problem with your second code is that B does not override foo. Hence B is still an abstract class. And you are attempting to instantiate it.

In the first version of the code the only pure function B inherited from A was the destructor, and a non-pure definition for the destructor was provided in B. So, B was is no longer abstract class and can be legally instantiated.

In the second version of the code B inherits two pure virtual functions from A - the destructor and foo. Since you did not override foo in B, B is still an abstract class and cannot be instantiated.

That's all there is to it. The error has nothing to do with the ability to provide a body for a pure virtual function in namespace scope.

0
R Sahu On

When I compile the above program using g++ 4.8.2, I get the following messages:

Compiler command:

g++ -Wall -std=c++11     socc.cc   -o socc

Error messages:

socc.cc:17:12: error: cannot allocate an object of abstract type ‘B’
 A *a = new B;
            ^
socc.cc:12:8: note:   because the following virtual functions are pure within ‘B’:
 struct B : A
        ^
socc.cc:9:6: note:  virtual void A::foo()
 void A::foo(){ }
      ^
make: *** [socc] Error 1

The gist of the error message is that B is an abstract type since it doesn't provide an overriding void foo();, which is declared as a pure virtual function in the base class.

The definition of A::foo() is not illegal. The following program works just fine:

#include <iostream>

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

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

struct B : A
{
    ~B(){ std::cout << "~B()" << std::endl; }
     void foo() {}  // Need this to be able to instantiate B.
};

A *a = new B;

int main()
{
    delete a;
}