Home > Back-end >  Problem creating abstract class with no virtual pure methods C
Problem creating abstract class with no virtual pure methods C

Time:06-26

I want to create a class that is a subclass of two classes that have a common virtual base class. Furthermore, I want this class to be abstract (not be able to create instances of it, but also not needing to call the ctor of the virtual base class).

Sample code:

#include <cstdio>
class CommonBaseClass {
public:
    virtual void DoSomething() = 0;
    virtual void DoSomethingElse() = 0;

    CommonBaseClass(int a) {}
};

class ClassA : public virtual CommonBaseClass {
public:
    virtual void DoSomething() override {
        printf("SOMETHING\n");
    }
    ClassA() {};
};

class ClassB : public virtual CommonBaseClass {
public:
    virtual void DoSomethingElse() override {
        printf("SOMETHING ELSE\n");
    }
    ClassB() {};
};

class TargetClass : //I will never instantiate this class
    public ClassA,
    public ClassB
{
public:
    TargetClass() : ClassA(), ClassB() {} //I don't want to call the CommonBaseClass ctor
};

class SubclassOfTarget :
    public TargetClass
{
public:
    SubclassOfTarget(int a) : CommonBaseClass(a), TargetClass()
    {}
};

int main()
{
    SubclassOfTarget c(15);
    c.DoSomething();
    c.DoSomethingElse();
}

If you try to compile this program, you will see that the compiler complains that TargetClass does not call the ctor of CommonBaseClass.

CodePudding user response:

It's true (since C 11) the constructors of an abstract class don't need to initialize their virtual base classes. The usual way to make a class abstract without any specific unimplemented virtual functions is to make the destructor pure virtual.

With this change, your program compiles:

class TargetClass : //I will never instantiate this class
    public ClassA,
    public ClassB
{
public:
    TargetClass() : ClassA(), ClassB() {} //I don't want to call the CommonBaseClass ctor

    virtual ~TargetClass() = 0;
};
TargetClass::~TargetClass() = default;

Note the destructor must be defined, even though it is pure. Since one declaration can't have both = 0 and a {body} or = default, that destructor definition in this case needs to be outside the class definition.

Though actually, it's recommended to always make sure any polymorphic class (having at least one virtual function or virtual base class) has a virtual destructor. This makes it legal to delete a pointer of base class type pointing at an object with a different dynamic type. And with the usual vtable implementations, there's nearly no cost to add the virtual destructor to a class which is already polymorphic. Following this advice, you would also add virtual ~CommonBaseClass() = default; to CommonBaseClass, and then the other classes automatically also have virtual destructors. And then you might use the style ~TargetClass() override = 0; for the declaration of the pure virtual destructor.

CodePudding user response:

You can use a pure virtual destructor as follows. Even although it is pure virtual, you still need to implement it. You do not need to declare destructors in the derived classes.

class TargetClass : //I will never instantiate this class
    public ClassA,
    public ClassB
{
public:
    TargetClass() : ClassA(), ClassB() {} //I don't want to call the CommonBaseClass ctor
    virtual ~TargetClass() = 0;
};

class SubclassOfTarget :
    public TargetClass
{
public:
    SubclassOfTarget(int a) : CommonBaseClass(a), TargetClass()
    {}
};

TargetClass::~TargetClass()
{}

int main()
{
    SubclassOfTarget c(15);
    c.DoSomething();
    c.DoSomethingElse();
}
  • Related