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?
Remove the call to a pure virtual function in the constructor of Base
.
Call someMethod
in the constructor of the derived class that overrides it instead.
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.
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 .
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:
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.