Does C++ create default "Constructor/Destructor/Copy Constructor/Copy assignment operator" for pure virtual class?
Asked Answered
G

4

9

Do C++ compilers generate the default functions like Constructor/Destructor/Copy-Constructor... for this "class"?

class IMyInterface
{
    virtual void MyInterfaceFunction() = 0;
}

I mean it is not possible to instantiate this "class", so i think no default functions are generated. Otherwise, people are saying you have to use a virtual destructor. Which means if i dont define the destructor virtual it will be default created, not virtual.

Furthermore i wannt to know if it is reasonable to define a virtual destructor for a pure virtual Interface, like the one above? (So no pointers or data is used in here, so nothing has to be destructed)

Thanks.

Gypsy answered 23/1, 2014 at 11:33 Comment(2)
= 0; is only allowed to follow virtual function.Burden
@Burden and Lightness Races in Orbit: Fixed itGypsy
W
1

Furthermore i wannt to know if it is reasonable to define a virtual destructor for a pure virtual Interface, like the one above? (So no pointers or data is used in here, so nothing has to be destructed)

It's not only reasonable, it's recommended. This is because in the case of virtual function hierarchies, (automatically) calling a destructor of a specialized class also calls all destructors of it's base classes. If they are not defined, you should get a linking error.

If you define at least one virtual function in your class you should also define a virtual destructor.

The destructor can be defined with =default though:

Here's a corrected (compilable) code example:

class ImyInterface
{
    virtual void myInterfaceFunction() = 0;
    virtual ~ImyInterface() = 0;
}

ImyInterface::~ImyInterface() = default;
Wiburg answered 23/1, 2014 at 11:40 Comment(1)
The definition would need to go in the .cpp file, or else you should add the inline keyword. Also, what's the point in defining the destructor as pure virtual when another member has already marked the class as abstract?Cacoepy
B
5

Yes.

There is no wording that requires the class to be instantiable in order for these special member functions to be implicitly declared.

This makes sense — just because you cannot instantiate the Base, doesn't mean a Derived class doesn't want to use these functions.

struct Base
{
   virtual void foo() = 0;
   int x;
};

struct Derived : Base
{
   Derived() {};         // needs access to Base's trivial implicit ctor
   virtual void foo() {}
};

See:

  • §12.1/5 (ctor)
  • §12.8/9 (move)
  • §12.8/20 (copy)
Bassett answered 23/1, 2014 at 11:41 Comment(2)
“Doesn’t want to use these functions” is of course a very soft way of putting it – I don’t see any way the constructor and destructor could even avoid it. After all, the base class constructor is called before the body of the derived class constructor is ever entered, and vice versa for the destructors.Caitlin
@ChristopherCreutzig: Indeed.Bassett
W
1

Furthermore i wannt to know if it is reasonable to define a virtual destructor for a pure virtual Interface, like the one above? (So no pointers or data is used in here, so nothing has to be destructed)

It's not only reasonable, it's recommended. This is because in the case of virtual function hierarchies, (automatically) calling a destructor of a specialized class also calls all destructors of it's base classes. If they are not defined, you should get a linking error.

If you define at least one virtual function in your class you should also define a virtual destructor.

The destructor can be defined with =default though:

Here's a corrected (compilable) code example:

class ImyInterface
{
    virtual void myInterfaceFunction() = 0;
    virtual ~ImyInterface() = 0;
}

ImyInterface::~ImyInterface() = default;
Wiburg answered 23/1, 2014 at 11:40 Comment(1)
The definition would need to go in the .cpp file, or else you should add the inline keyword. Also, what's the point in defining the destructor as pure virtual when another member has already marked the class as abstract?Cacoepy
C
1

Furthermore i wannt to know if it is reasonable to define a virtual destructor for a pure virtual Interface, like the one above? (So no pointers or data is used in here, so nothing has to be destructed)

Will the derived classes ever do anything in their destructors? Can you be certain they never will, even when somebody else takes over development?

The whole point of having a virtual destructor is not to make sure the base class is properly destructed, that will happen anyway. The point is that the derived class's destructor is called when you use a generic interface:

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

class B : public A {
  std::ifstream fh;
public:
  virtual ~B() {}
  virtual int f() { return 42; }
};

std::shared_ptr<A> a = new B;

When a goes out of scope, why is the ifstream closed? Because the destructor deletes the object using the virtual destructor.

Caitlin answered 23/1, 2014 at 14:12 Comment(0)
C
0

This addresses the second question about declaring a virtual destructor for an abstract base class (e.g. at least one member function is pure virtual). Here is a real world example of the LLVM clang++ compiler catching a potential problem. This occurred with the command line tools version supplied by Apple Developer for the Mac OS X Mavericks operating system.

Suppose you have a collection of derived classes that ultimately have the parent with the abstract base class to define the common interface. Then it is necessary to have a storage container like a vector that is intentionally declared to store a pointer to the abstract base class for each element. Later on, following good engineering practices, the container elements need to be "deleted" and the memory returned to the heap. The simplest way to do this is to traverse the vector element by element and invoke the delete operation on each one.

Well, if the abstract base class does not declare the destructor as virtual, the clang++ compiler gives a friendly warning about calling the non-virtual destructor on an abstract class. Keep in mind that in reality only the derived classes are allocated from the heap with operator new. The derived class pointer type from the inheritance relationship is indeed the abstract base class type (e.g. the is-a relationship).

If the abstract base class destructor is not virtual, then how will the correct derived class' destructor be invoked to release the memory? At best the compiler knows better (at least potentially does with C++11), and makes it happen. If the -Wall compiler option is enabled, then at least the compilation warning should appear. However, at worse, the derived class destructor is never reached and the memory is never returned to the heap. Hence there is now a memory leak that may be very challenging to track down and fix. All it will take is a single addition of "virtual" to the abstract base class destructor declaration.

Example code:

class abstractBase
{
    public:
       abstractBase() { };
       ~abstractBase() { };

       virtual int foo() = 0;
};


class derived : abstractBase
{
    public:
        derived() { };
        ~derived() { };

        int foo() override { return 42; }
};

//
// Later on, within a file like main.cpp . . .
// (header file includes are assumed to be satisfied)
// 
vector<abstractBase*> v;

for (auto i = 0; i < 1000; i++)
{
    v.push_back(new derived());
}



//
// do other stuff, logic, what not
// 


// 
// heap is running low, release memory from vector v above 
//    
for (auto i = v.begin(); i < v.end(); i++)
{
    delete (*i); // problem is right here, how to find the derived class' destructor?
}

To resolve this potential memory leak, the abstract base class has to declare its destructor as virtual. Nothing else is required. The abstract base class now becomes:

class abstractBase
{
    public:
       abstractBase() { };
       virtual ~abstractBase() { };   // insert virtual right here

       virtual int foo() = 0;
}

Note that the abstract base class has currently empty constructor and destructor bodies. As Lightness answered above, the compiler creates a default constructor, destructor, and copy constructor for an abstract base class (if not defined by the engineer). It is highly recommended to review any of The C++ Programming Language editions by the C++ creator, Bjarne Stroustrup, for more details on abstract base classes.

Creaturely answered 19/2, 2014 at 11:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.