destructors
In general, when implementing abstract base classes, you have two recommended options for destructors ( source ):
1. Implementation of a public virtual destructor
Use this when you intend to have pointers to your base class, which can point to instances of the derived class. For instance:
class MyBase { public: virtual ~MyBase() {}; }; class MyDerived : public MyBase { public: virtual ~MyDerived() {}; } std::unique_ptr<MyBase> pInstance = std::make_unique<MyDerived>();
By making the destructor virtual in the base class (as well as in the derived class), you will see that the destructor for MyDerived is called at run time. If the destructor is not virtual, calling delete on a pointer to MyBase will NOT call the MyDerived destructor .
2. Implementation of a secure, non-virtual destructor
Use this in cases where you do not want to allow the user to create base class pointers for your derived object.
class MyBase { protected: ~MyBase() {}; }; class MyDerived : public MyBase { public: ~MyDerived() {}; }
This is due to an important warning. If you have a deep inheritance hierarchy, having a non-virtual destructor means that you must enforce this rule right down to your hierarchy. For instance:
class MyBase { protected: ~MyBase() {}; }; class MyDerived : public MyBase { public: ~MyDerived() {}; } class MyDerivedAgain : public MyDerived { public: ~MyDerivedAgain() {}; }
If you decide to go this route, you must make sure that you are not allowing any of your base classes to be created. All destructors, except for sheet-based classes, must be protected .
This seems a bit confusing, but it may have advantages such as avoiding vtable space and a mild performance improvement in narrow loops by avoiding vtable viewing at runtime (at best, micro-optimization).
Constructors
It is perfectly normal to omit the constructor in any class if all variables can be built by default (or do not have a constructor (for example, int)). The C ++ compiler will simply create the default MyAbstractClass::MyAbstractClass() { } . However, it is usually preferable to create a constructor to initialize any abstract class variables:
Good:
class MyBase { protected: int _x; int _y; }; class MyDerived : public MyBase { public: MyDerived(int x, int y) { _x = x; _y = y; } };
It is better:
class MyBase { public: MyBase(int x, int y) : _x(x), _y(y) { } protected: int _x; int _y; }; class MyDerived : public MyBase { public: MyDerived(int x, int y) : MyBase(x, y) { } };
The "better" version with the constructor MyBase::MyBase(int, int) better because it immediately initializes _x and _y , and the compiler checks that the constructor of the base class is called . By initializing the variables of the base class in the derived constructor, you potentially cause a catastrophe, because that you can forget to initialize the variable and cause all kinds of run-time problems.
Appendix: Note to "Interfaces"
If you implement an interface class that defines a "contract", you can skip the constructor (interfaces have no variables or implementations, no constructor is required) and use a public virtual destructor. This ensures that any class that implements the interface is cleared when it is deleted.
class MyInterface { public: virtual ~MyInterface() = 0; virtual void MyMethod() = 0; virtual void MyOtherMethod() = 0; };