Destructor and constructor for C ++ abstract base class

I was looking for this, but I did not quite understand the answers.

I'm completely new to C ++, and I'm trying to get an abstract class that serves as the base class for my object types so that I can store my objects in an array of pointers like abstract instead of using void * . In addition, my objects have several common member functions that can easily reduce my code base with an abstract class implementation.

However, I got confused in the constructor and destructor of the abstract class.

The abstract class really does not need a constructor, since the parameters that can be passed to them are common to both, they require different actions with the specified parameter in the derived class to correctly set the protected attributes (matrix calibration). So, is it ok to have a constructor? Also, since I don't have a constructor, what should a destructor be like?

I say the answer, where it was necessary to implement a virtual destructor. However, I'm not sure what that means, and there has been a discussion about potential memory leaks saying that they will not happen if derived classes override the destructor. So this means that I can implement a virtual deconstructor, and then in the derived objects say Foo and Bar I just implement ~Foo and ~Bar to prevent memory leak (provided that they are true, of course)? I was not sure I understood what it meant to re-implement in derived classes.

+5
source share
2 answers

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() {}; } // NOT ALLOWED: std::unique_ptr tries to call protected destructor. std::unique_ptr<MyBase> pBadInstance = std::make_unique<MyDerived>(); // Allowed: std::unique_ptr calls public MyDerived::~MyDerived() std::unique_ptr<MyDerived> pGoodInstance = std::make_unique<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() {}; } // Uh oh! MyDerivedAgain destructor would not be called! std::unique_ptr<MyDerived> pGoodInstance = std::make_unique<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; }; // Base class virtual destructors should always have an implementation, // even when they are pure-virtual. MyInterface::~MyInterface() { } // ----------------------------------------------------------------------------- class MyImplementation : public MyInterface { virtual ~MyImplementation () { } virtual void MyMethod() { std::cout << "MyMethod()" << std::endl; } virtual void MyOtherMethod() { std::cout << "MyOtherMethod()" << std::endl; } }; 
+8
source

In general, abstract classes in C ++ should provide a virtual destructor definition. It can also be made abstract.

  virtual ~MyClass() = 0; // Define a body in any case MyClass::~MyClass() {} 

An abstract class does not need to declare a constructor (which cannot be a pure virtual BTW function).

A constructor may make sense when your abstract class is not a simple interface (no data elements).

+1
source

Source: https://habr.com/ru/post/1259942/


All Articles