简体   繁体   中英

Problem with abstract class inheritance and constructor at C++

class Base {
public:
    Base(int a) : a_(a) {
        //do something
        someMethod();
        //do something else
    };
protected:
    int a_;
    virtual void someMethod() = 0 {};
};

class Derived : Base {
public:
    Derived() {
        Base::Base(42);
    }
protected:
    void someMethod() override {
        //realisation
    }
};

int main() {
    Derived *obj = new Derived();
    delete obj;
}

This code doesn't work by two mistakes: base class's default constructor is needed and base class's constructor with parameters can't be called because of using abstract methods

My problem is that someMethod() realised in class Derived is not called at all when I create object of class Derived . Also I don't want to use default constructor of class Base , but compiler is swearing.

How can I correct my code to see functionality that I want?

How can I correct my code to see functionality that I want?

  1. Remove the call to a pure virtual function in the constructor of Base .

  2. Call someMethod in the constructor of the derived class that overrides it instead.

  3. Provide an initialiser to the Base subobject in the member initiliser list. If you don't provide an initialiser to the base, it will be default initialised.

Why this cannot work?

This design will not work because of the way obects are constructed.

When you construct a Derived , the first thing happening is that a Base object is constructed with a Base constructor. There is no Derived object at this moment, so if you'd invoke the virtual function in the Base constructor, it would be the virtual that would be valid for the Base class until you leave the Base constructor's body.

This is allowed by the standard, but with restrictions:

[base.class.init]/16 : Member functions ( including virtual member functions ) can be called for an object under construction. (...) However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the program has undefined behavior.

These restriction do not apply to virtual functions that are called from the constructor body, since the body is executed after all initializers.

But in your case the virtual function is pure virtual for the Base . So it's UB according to the following clause:

[class.abstract]/6 : Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined .

What is the alternative

There is unfortunately no other real alternative than using a two step initialization in which you first construct the object and then call an initialization function before using the object.

The only issue with this approach is the risk of forgetting the call to the initialization function. You can protect you against this:

  • using a flag to indicate if the intialization has taken place and check this flag in all member functions (yes, it's a little overhead).
  • if you have an abstract class, you may perhaps use a factory pattern (factory method or abstract factory). You could then let the factory do the call.
  • you may use the builder pattern, and make sure that the constructor is only visible to the builder who won't forget the initialization either.

Other problems with your code

You must be careful about how you "call" the base constructor from the derived constructor:

class Derived : Base {
public:
    Derived() : Base(42) // this is the correct place !
    {  
    //Base::Base(42);  //<====  OUCH !!! NO !! This creates a temporary base object !!
    }
    ...
};

You'd also need to be careful about the pure virtuals (I don't know if it's a typo or if your compiler could compile your code):

virtual void someMethod() = 0;  // if it's abstract, no pending {} !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM