Virtual base class and inheritance - c++

While scrolling through SO, I found this question
#include <iostream>
using namespace std;
class base
{
public:
base()
{
cout << "ctor in base class\n";
}
};
class derived1 : public base
{
public:
derived1()
{
cout <<"ctor in derived class\n";
}
};
int main()
{
derived1 d1obj;
return 0;
}
There was this question :- When d1obj is created, the control first reaches the base class constructor and then it goes to the derived class constructor? Or is it the other way round : It first reaches the derived class constructor, finds that it has base class and so the control goes to the constructor in base class?
and the aswer contained the part
When a class has virtual bases it's common for a constructor to result in two different function bodies being emitted - one for use when this class is the most derived type, and one for use when this class is itself a base class. The reason is that virtual base classes are constructed by the most-derived class, to ensure that when they're shared they're only constructed once. So the first version of the constructor will call all base class constructors, whereas the second version will only call constructors for non-virtual bases.
can anyone explain to me this with an example ?
Here is the link for that question

In your example it is the default constructor of derived1 that is responsible for calling the default constructor of base. However, this is only necessary when derived1 is the actual (most derived) object, as in your example
int main()
{
derived1 d1obj; // Most derived object of type `derived1`
// It contains a direct `base` subobject
// Constructor of `derived1` must construct `base` subobject as well
}
But when derived1 is used a base subobject of a larger object
class derived2 : public derived1
{
public:
derived2()
{
cout <<"ctor in derived 2 class\n";
}
};
int main()
{
derived2 d2obj; // Most derived object of type `derived2`
// It contains a direct `derived1` subobject and an indirect `base` subobject
// (through `derived1`)
// Constructor of `derived2` must directly construct both `derived1` subobject and
// `base` subobject
// Which means that constructor of `derived1` subobject should not attempt
// to construct `base` subobject
}
then it is the constructor of derived2 that is responsible for calling both the default constructor of derived1 and the default constructor base. In this case the default constructor of derived1 shall not call the constructor of base, since it will lead to double-construction of base.
To satisfy all of these requirements derived1 will typically have two versions of its default constructor: full version called in your original example and "reduced" version called from derived2 in my example above.
Alternatively, derived1's default constructor can be implemented with a hidden boolean parameter, which will tell it whether to call base's default construictor or not.

"When a class has virtual bases it's common for a constructor to result in two different function bodies being emitted - one for use when this class is the most derived type, and one for use when this class is itself a base class. The reason is that virtual base classes are constructed by the most-derived class, to ensure that when they're shared they're only constructed once. So the first version of the constructor will call all base class constructors, whereas the second version will only call constructors for non-virtual bases."
in this the answerer actually wants to say about a situation common in C++ known as dreaded diamond in multiple inheritance.
to understand just see the most upvoted answer to this link
In C++, what is a virtual base class?

Related

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?
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.
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 {} !

"Middle classes" in diamond inheritance graph using non-default virtual base constructor: why is it not a compile error?

Consider a diamond inheritance graph (i.e., virtual base class). We know from previous
questions
that on construction the most derived class directly calls the default (0-arg) constructor of the (virtual) base.
But we also know from answers to the previous question (e.g., here
that if the "middle" classes in the diamond have constructors that are used by the most-derived class and those constructors "call" non-default constructors of their (virtual) base class (via the initialization list) then that is not respected … though the bodies of the "middle" classes' constructors are executed.
Why is that? I would have thought it should be a compile error. (Detected, of course, when the most-derived class is declared and the diamond is created.)
I'm looking for two things:
where in the standard is this specified?
does this kind of explicit-yet-ignored code happen anywhere else in the language?
Code sample of what I'm talking about follows its actual and expected outputs below:
B 0arg-ctor
Mf 0arg-ctor
Mt 0arg-ctor
useD
expected output:
ERROR: (line 19) struct `D` creates a diamond inheritance graph where an explicitly
written invocation of a virtual base class constructor is ignored (for base
classes `Mf`and `Mt` and ancestor virtual base class `B`
code:
#include <iostream>
using namespace std;
struct B {
B() noexcept { cout << "B 0arg-ctor" << endl; };
B(bool) noexcept { cout << "B 1arg-ctor" << endl; };
};
struct Mf : public virtual B
{
Mf() : B(false) { cout << "Mf 0arg-ctor" << endl; }
};
struct Mt : public virtual B
{
Mt() : B(true) { cout << "Mt 0arg-ctor" << endl; }
};
struct D : public Mf, public Mt { };
void useD(D) { cout << "useD" << endl; }
int main()
{
D d;
useD(d);
return 0;
}
The rules for initializing bases and members are specified in [class.base.init].
Specifically in p7:
A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
and its complement in p13:
First, and only for the constructor of the most derived class ([intro.object]), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
Hence the initializers B(true) and B(false) are ignored when initializing Mf and Mt because they're not the most derived class, and the initialization of D leads with the initialization of B. No initializer for it is provided, so B() is used.
Making this fail to compile would be basically impossible? To start with, consider:
struct Mf : public virtual B { };
struct D : public Mf { };
That initializes B, but implicitly. Do you want that to be an error for Mf since its initialization would be ignored? I assume no - otherwise this language feature would be completely unusuable. Now, what about:
struct Mf : public virtual B { Mf() : B() { } };
struct D : public Mf { };
Is that an error? It basically means the same thing though. What if Mf had members that needed to be initialized and I, as matter of habit, just like listing the base classes?
struct Mf : public virtual B { Mf() : B(), i(42) { } int i; };
struct D : public Mf { };
Okay, you say, you only error if you actually provide arguments. Which is where a different misconception comes in:
We know from previous questions that on construction the most derived class directly calls the default (0-arg) constructor of the (virtual) base.
That's not true (and is not what those answers state). The most derived class initializes the virtual bases - but this initialization does not have to be default. We could've written:
struct D : public Mf, public Mt { D() : B(true) { } };
And really, there's not an interesting distinction between B() and B(true). Imagine the constructor were just B(bool = true), then does it matter whether or not the user provides the argument true? It would be strange if one were an error but not the other, right?
If you keep going down this rabbit hole, I think you'll find that making this an error would be either exceedingly narrow or exceedingly restrictive.
[class.mi]/7 - For an object of class AA, all virtual occurrences of base class B in the class lattice of AA correspond to a single B subobject within the object of type AA...
[class.base.init]/7 - ... A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
[intro.object]/6 - If a complete object, a data member, or an array element is of class type, its type is considered the most derived class, to distinguish it from the class type of any base class subobject; an object of a most derived class type or of a non-class type is called a most derived object.
Why is that?
Apart from the obvious; because the standard says so, one possible rationale is that since you only have one base class subobject it doesn't even make sense to allow middle bases to interact with the initialization of the virtual base. Otherwise, which middle base class would you expect to initialize the virtual base, Mt or Mf ?, because for B(false) and B(true) would mean two different way to initialize the same object.
Adding a new class to a codebase should not cause well-formed classes to suddenly become invalid. That would be a language disaster. If Derived initializes its virtual base Base, and it is correct code, then the existence of a further-derived class should have no impact on the validity of Derived. Your expectation would almost completely preclude inheritance from any class simply because it happens to use virtual inheritance somewhere, and make virtual inheritance unusable.
But for the citations you requested (from draft n4762):
10.9.2/13:
In a non-delegating constructor, initialization proceeds in the following order:
— First, and only for the constructor of the most derived class (6.6.2), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
And the second part you asked about, the virtual base initializer in a non-most-derived class is described here, in 10.9.2/7:
A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
A virtual base is constructed by the most-derived class, but need not use a default constructor to do so, it can use any accessible constructor. Intermediate bases simply do not factor into the construction of a virtual base.

Dynamic binding inside constructor for virtual Function in C++

As per the standard, we know that constructor always go for an early binding of a virtual function inside them because they don't have complete idea the derived class hierarchy downside.
In this case if early binding is used inside my base constructor, I have passed a derived object to a base class pointer which is completely acceptable (an upcasting is done here). If early binding is used the selection of the virtual function should be based on the type of the pointer (which is Base * here) but not the content of the pointer(the object pointed by the pointer because we don't know the exact object being pointed). In that case since the pointer type is Base * we should have invoked only Base class virtual function in both cases. Could some one please clarify this?
I think dynamic binding is used here rather than early binding. Please correct me if my understanding is wrong.
The first line of the output which invokes base is completely fine
class Base
{
public:
Base(){
fun();
}
Base(Base *p)
{
p->fun();
}
virtual void fun()
{
cout<<"In Base"<<endl;
}
};
class Derived : public Base
{
public:
void fun()
{
cout<<"In Derived"<<endl;
}
};
int main()
{
Derived d;
Base b(&d);
}
O/P :
In Base
In Derived
The rule for virtual calls within a constructor body applies to an object currently being constructed, because that object is not yet considered to be an object of any derived class. (And there's a similar rule for an object currently being destroyed.) It has little to do with "early binding" in the sense of using a compile-time type, such as the syntax ClassName::member_func() forces.
Your code has two different objects d and b, and the constructor of d has entirely finished by the time you get to the p->fun(); line.
In detail:
The program enters main.
The object d is created using the implicitly declared default constructor of Derived.
The first thing Derived::Derived() does is create the base class subobject, by calling the default constructor Base::Base().
The body of Base::Base() calls fun(). Since we have not yet entered the body of the Derived::Derived() constructor, this virtual lookup invokes Base::fun().
Base::Base() finishes.
The body of Derived::Derived(), which is empty, executes and finishes.
Back in main, the object b is created by passing a pointer to d to the constructor Base::Base(Base*).
The body of Base::Base(Base *p) calls p->fun(). Since p is a pointer to d, which is already a completely constructed object of type Derived, this virtual lookup invokes Derived::fun().
Contrast with this slightly different example, where we define a default constructor of Derived to pass this (implicitly converted to Base*) to the constructor for the Base subobject. (This is valid, though could be risky if the pointer were used in other ways, such as in an initializer for a base or member of Base.)
#include <iostream>
using std::cout;
using std::endl;
class Base
{
public:
Base(){
fun();
}
Base(Base *p)
{
p->fun();
}
virtual void fun()
{
cout<<"In Base"<<endl;
}
};
class Derived
{
public:
Derived() : Base(this) {}
virtual void fun() override
{
cout << "In Derived" << endl;
}
};
int main()
{
Derived d;
}
This program will print just "In Base", since now in Base::Base(Base *p), p does point at the same object which is currently being constructed.
The reason is that C++ classes are constructed from Base classes to derived classes and virtual call table of the complete object is created when the object creation process is completed. Therefore, the base class function is called in the code excerpt above. Unless otherwise mandatory, you should never make virtual function calls in the constructor. Below is an excerpt from Bjarne Stroustrup's C++ Style and Technique FAQ:
In a constructor, the virtual call mechanism is disabled because
overriding from derived classes hasn’t yet happened. Objects are constructed from the base up, “base before derived”.
Destruction is done “derived class before base class”, so virtual
functions behave as in constructors: Only the local definitions are used –
and no calls are made to overriding functions to avoid touching the (now
destroyed) derived class part of the object.

C++ Type changes during derived class construction - virtual function question

C++ type change during deletion
I've read that when you construct a derived type, the type changes depending on which constructor is being called. So, if you create a derived object and call a virtual function using a base pointer, normally it would map to the implementation in the derived class. If you called the virtual function in the base class constructor though, it would use the base class implementation as the type of the object is technically that of the base class while in that function. For example (makeshift code, sorry if it doesn't compile):
class Base {
Base()
{
std::cerr << "Base Constructor.";
func();
}
virtual void func() {
std::cerr << "Func base called." << std::endl;
}
};
class Derived : public Base {
Derived()
{
std::cerr << "Derived Constructor.";
func();
}
void func() {
std::cerr << "Func derived called." << std::endl;
}
};
int main() {
Derived* d = new Derived;
delete d;
}
Should output:
Base Constructor.
Func base called.
Derived Constructor.
Func derived called.
First of all, is this always true or is it implementation dependent?
If I used RTTI and typeinfo, would the type printed in the base actually be that of the base, or is this more of an unwritten rule sort of situation?
Is it dangerous to call virtual functions from constructors with this in mind, or is it safe as long as you know what you're doing?
To keep it short and simple, you can have a Rule:
The virtual mechanism is disabled in Constructors and Destructors
A virtual function call in Base class will always call the base class version of the function, the same in derived class results in call to the Derived class version of the function.
First of all, is this always true or is it implementation dependent?
Yes this is always true. This is not implementation-dependent.
If I used RTTI and typeinfo, would the type printed in the base actually be that of the base?
Yes it would be of Base; Derived object doesn't even exist while you are in Base class constructor.
Is it dangerous to call virtual functions from constructors with this in mind, or is it safe as long as you know what you're doing?
No it is not dangerous to call virtual functions from constructor as long as you understand the semantics behind it.
This C++ FAQ should be a good read for you.
It's well-defined.
[n3290: 12.7/4]: Member functions, including virtual functions
(10.3), can be called during construction or destruction (12.6.2).
When a virtual function is called directly or indirectly from a
constructor or from a destructor, including during the construction or
destruction of the class’s non-static data members, and the object to
which the call applies is the object (call it x) under construction or
destruction, the function called is the final overrider in the
constructor’s or destructor’s class and not one overriding it in a
more-derived class. If the virtual function call uses an explicit
class member access (5.2.5) and the object expression refers to the
complete object of x or one of that object’s base class subobjects but
not x or one of its base class subobjects, the behavior is undefined.
There is an excellent article from Scott Meyers. It is from his book Effective C++.
The article can be found at:
Never Call Virtual Functions during Construction or Destruction
It also discusses an alternative implementation.
Recently I had a similar problem which I solved this way:
class EthernetFrame
{
protected:
/** ctor to be called from derived classes */
EthernetFrame(unsigned inPayloadLength)
{
calculatePadBytes(inPayloadLength);
}
private:
/** calculates needed required PadBytes for Frames < 64B
* #param inPayloadLength we need to know the length of the actual L3 frame
*/
void calculatePadBytes(unsigned inPayloadLength);
};
class IPv4Frame : public EthernetFrame
{
public:
/** create empty IPv4 packet */
IPv4Frame() :
EthernetFrame(cIPv4_MINIMUM_LENGTH)
{};
// IPv4 header + trailer in bytes
unsigned cIPv4_MINIMUM_LENGTH;
protected:
/** ctor to be called from derived classes */
IPv4Frame(unsigned inPayloadLength) :
EthernetFrame(cIPv4_MINIMUM_LENGTH+inPayloadLength)
{};
};

Why base class destructor (virtual) is called when a derived class object is deleted?

A difference between a destructor (of course also the constructor) and other member functions is that, if a regular member function has a body at the derived class, only the version at Derived class gets executed. Whereas in case of destructors, both derived as well as base class versions get executed?
It will be great to know what exactly happens in case of destructor (maybe virtual) & constructor, that they are called for all its base classes even if the most derived class object is deleted.
Thanks in advance!
The Standard says
After executing the body of the destructor and destroying any automatic objects allocated within the body,
a destructor for class X calls the destructors for X’s direct non-variant members,the destructors for X’s direct
base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for
X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is,
ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed
in the reverse order of the completion of their constructor (see 12.6.2). A return statement (6.6.3) in a
destructor might not directly return to the caller; before transferring control to the caller, the destructors
for the members and bases are called. Destructors for elements of an array are called in reverse order of
their construction (see 12.6).
Also as per RAII resources need to be tied to the lifespan of suitable objects and the destructors of respective classes must be called upon to release the resources.
For example the following code leaks memory.
struct Base
{
int *p;
Base():p(new int){}
~Base(){ delete p; } //has to be virtual
};
struct Derived :Base
{
int *d;
Derived():Base(),d(new int){}
~Derived(){delete d;}
};
int main()
{
Base *base=new Derived();
//do something
delete base; //Oops!! ~Base() gets called(=>Memory Leak).
}
Constructor and destructor are different from the rest of regular methods.
Constructor
can't be virtual
in derived class you either call explicitly constructor of base class
or, in case where you don't call base class constructor compiler will insert the call. It will call the base constructor without parameters. If no such constructor exists then you get compiler error.
struct A {};
struct B : A { B() : A() {} };
// but this works as well because compiler inserts call to A():
struct B : A { B() {} };
// however this does not compile:
struct A { A(int x) {} };
struct B : A { B() {} };
// you need:
struct B : A { B() : A(4) {} };
Destructor:
when you call destructor on derived class over a pointer or a reference, where the base class has virtual destructor, the most derived destructor will be called first and then the rest of derived classes in reversed order of construction. This is to make sure that all memory has been properly cleaned. It would not work if the most derived class was called last because by that time the base class would not exists in memory and you would get segfault.
struct C
{
virtual ~C() { cout << __FUNCTION__ << endl; }
};
struct D : C
{
virtual ~D() { cout << __FUNCTION__ << endl; }
};
struct E : D
{
virtual ~E() { cout << __FUNCTION__ << endl; }
};
int main()
{
C * o = new E();
delete o;
}
output:
~E
~D
~C
If the method in base class is marked as virtual all the inherited methods are virtual as well so even if you don't mark the destructors in D and E as virtual they will still be virtual and they still get called in the same order.
This is by design. The destructor on the base class must be called in order for it to release its resources. Rule of thumb is that a derived class should only clean up its own resources and leave the base class to clean up itself.
From C++ spec:
After executing the body of the
destructor and destroying any
automatic objects allocated within the
body, a destructor for class X calls
the destructors for X’s direct
members, the destructors for X’s
direct base classes and, if X is the
type of the most derived class
(12.6.2), its destructor calls the
destructors for X’s virtual base
classes. All destructors are called as
if they were referenced with a
qualified name, that is, ignoring any
possible virtual overriding
destructors in more derived classes.
Bases and members are destroyed in the
reverse order of the completion of
their constructor (see
12.6.2).
Also, because there is only one destructor, there is no ambiguity as to which destructor a class must call. This is not the case for constructors, where a programmer must pick which base class constructor should be called if there isn't an accessible default constructor.
Because that's how dtor's work. When you create an object, ctors are invoked starting from the base, and going all the way to the most derived. When you destroy objects (correctly) the reverse happens. The time that making a dtor virtual makes a difference is if/when you destroy an object via a pointer (or reference, though that's fairly unusual) to the base type. In that case, the alternative isn't really that only the derived dtor gets invoked -- rather, the alternative is simply undefined behavior. That make happen to take the form of invoking only the derived dtor, but it might take an entirely different form as well.
A base class destructor may be responsible for cleaning up resources that were allocated by the base class constructor.
If your base class has a default constructor (one that doesn't take parameters or has defaults for all its parameters) that constructor is automatically called upon construction of a derived instance.
If your base class has a constructor that requires parameters, you must call it manually in the initializer list of the derived class constructor.
Your base class destructor will always be automatically called upon deletion of the derived instance since destructors don't take parameters.
If you're using polymorphism and your derived instance is pointed to by a base class pointer, then the derived class destructor is only called if the base destructor is virtual.
As Igor says constructors must be called for base classes. Consider what would happen if it wouldn't be called:
struct A {
std::string s;
virtual ~A() {}
};
struct B : A {};
If the destructor for A would not be called when deleting a B instance, A would never be cleaned up.
When any object is destroyed, destructors run for all sub-objects. This includes both reuse by containment and reuse by inheritance.