This question is very similar to this one Why can't I dynamic_cast "sideways" during multiple inheritence?, except that the cast does work - just not inside in the constructor.
Header:
class A
{
public:
virtual ~A() {}
void printA();
};
class B
{
public:
B();
virtual ~B() {}
void printB();
private:
std::string message_;
};
class C : public A, public B
{
public:
C() {}
virtual ~C() {}
};
Source:
void A::printA() { cout << "A" << endl; }
B::B()
{
A* a = dynamic_cast< A* >( this );
if ( a ) {
message_ = std::string( "A and B" );
} else {
message_ = std::string( "B" );
}
}
void B::printB() { cout << message_.c_str() << endl; }
Main:
int main( int argc, char* argv[] )
{
cout << "Printing C..." << endl;
C c;
c.printA();
c.printB();
cout << "Checking again..." << endl;
cout << !!dynamic_cast< A* >( &c ) << endl;
return EXIT_SUCCESS;
}
Result:
Printing C...
A
B
Checking again...
1
So, the dynamic_cast does work for multiple inheritance (no surprises there!), but why not when called at runtime for the 'this' pointer inside B::B()? I thought that the object was fully formed once inside the body of the constructor i.e. all the memory was allocated for the component objects, they haven't been initialised yet. I appreciate that this depends on the superclass constructor order, but in this example A is called before B.
I am obviously not understanding what exactly is happening under the hood, can someone please enlighten me?
Thanks,
Cam Bamber.
Basically the standard says it will not work (dynamic_cast) during construction of an object.
<quote>
Edit: Added based on VJo comment below.
Note: The cast from a 'B' to an 'A' using dynamic cast should work because we are casting an object of type 'C'. If we added the following code to main:
B bObj;
B& bRef = c;
B* bPtr = &c;
std::cout << !!dynamic_cast<A*>(&bObj) << std::endl;
std::cout << !!dynamic_cast<A*>(&bRef) << std::endl;
std::cout << !!dynamic_cast<A*>( bPtr) << std::endl;
The extra output would be:
0 // Can not convert a B to an A
1 // Can convert this B to an A because it is really a C.
1 // This is what we are reeling doing in B::B() that fails
// It is not the dynamic_cast<> that fails but the conversion of this from C* to B*
// That is causing UB
It fails in the constructor because the object is not fully formed. Using this we are trying to convert a C pointer into a B pointer before the C constructor has started (the code defined by the user). Thus the use of this in B::B() as a pointer to a C object fails thus when the dynamic_cast<> is called on this it fails to do what you want it to because of UB.
12.7 Construction and destruction [class.cdtor]
Paragraph 3
To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
[ Example:
struct A { };
struct B : virtual A { };
struct C : B { };
struct D : virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X
{
E() : D(this), // undefined: upcast from E* to A*
// might use path E* → D* → A*
// but D is not constructed
// D((C*)this),
// defined:
// E* → C* defined because E() has started
// and C* → A* defined because
// C fully constructed
X(this) { // defined: upon construction of X,
// C/B/D/A sublattice is fully constructed
}
};
— end example ]
</quote>
Each base class constructor is executed before the derived class constructor, and during the B constructor, the dynamic type of the object is B; it does not become a C until you enter the C constructor. So you cannot do anything that requires a dynamic type of C: you can't cross-cast to any of Cs other base classes, and if you called a virtual function, then you would not get any overrides provided by C.
Under the hood, the dynamic type is (in most implementations at least) determined by a pointer in the object (known as the "vptr"), which points to some static data specifying properties of the class, including a table of virtual functions (known as the "vtable") and the information needed for dynamic_cast and typeid. Before each constructor, this is updated to point to the information for the class currently under construction.
During the construction of A then the dynamic type is A regardless. This is because you would start calling member functions of derived classes and accessing derived member variables before it's been constructed, which would be UB and very bad.
Since B doesn't inherit from A (B is parent-most class), the dynamic type of B during its constructor is B. Only when both the A and B parents are constructed can the child C be constructed, allowing for sideways dynamic_casting.
It doesn't work inside B, because B doesn't inherit from A
Related
#include <iostream>
class A
{
public:
virtual ~A() = default;
virtual void foo(void) = 0;
};
class B : public A
{
private:
int x;
public:
B(int a) : x(a) {}
void foo(void) { std::cout << "B: " << x << "\n"; }
};
class Foo
{
private:
A* a_ptr;
public:
Foo (B& x) { a_ptr = &x; }
A* get_ptr(void) { return a_ptr; }
void dummy(void) { std::cout << "Foo: "; std::cout << a_ptr << "\t "<< typeid(*a_ptr).name() << "\n"; a_ptr->foo(); std::cout << "\n"; }
};
int main(void)
{
B b(10);
Foo f(b);
f.dummy();
return 0;
}
If the constructor of Foo takes a reference to an object of B, then this program executes the way I expect it to, i.e. a_ptr->foo() calls B::foo().
However, if the constructor is changed to accept the parameter by value, then a_ptr->foo() resolves to A::foo(), and results in a pure virtual method called exception
Sample output (Passed by reference:):
Foo: 0x7fffe90a24e0 1B
B: 10
Sample output (Passed by value):
Foo: 0x7fffc6bbab20 1A
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
I've a vague hunch as to why this might be happening, and I'm looking for some literature or reference which might prove or disprove my hypothesis: When passed by reference, the base class pointer a_ptr points to an entity whose lifetime exceeds past the call to a_ptr->foo().
However, when passed by value, a_ptr points to a temporary which is lost when the constructor exits.
I suppose this has something to do with the VTABLE of A, but I can't quite put my finger on it.
Yes, your suspicion is correct.
When the B object is passed by value into the Foo constructor, it becomes a local variable of the constructor. The constructor is saving a pointer to that local object, which goes out of scope when the constructor exits.
So, the call to a_ptr->foo() in Foo::dummy() is actually undefined behavior since a_ptr doesn't even point at a valid object to begin with. But, it doesn't really crash since A::foo() doesn't use its this pointer for anything. It just points to a compiler-defined function that throws the pure virtual method called error, which you don't catch, so your program terminates.
You assigned temporary object B by reference to a_ptr which is of type A*. On constructor exit this temporary object has beed destroyed. As VTABLE has been destroyed too, called A::foo, which is pure virtual. So you got it.
Does C++ have existing method to check if an object is a derived-typed object? For example,
class A
{};
class B : public A
{};
A* p;
And check if p points to B.
If the class is polymorphic (i.e., has at least one virtual member function), you can use dynamic_cast or typeid.
Otherwise, no. Keeping track of an object's dynamic type has a cost, and the language was designed to avoid pessimizing code that has no need for it.
And check if p points to B.
You can use dynamic_cast for that, if there is at least one virtual member function in the class. It is common to make the destructor virtual.
class A
{
virtual ~A() {}
};
and then,
B* bPtr = dynamic_cast<B*>(p);
if ( bPtr )
{
// Use the pointer
}
Does C++ have existing method to check if an object is a derived-typed object?
There are actually two ways to achieve this:
A* p = new B();
B* pB = static_cast<B*>(p); // Checks if B is related to A in an inheritance
// ^^^^^^^^^^^^^^^^^^^ hierarchy. Fails to compile if not.
A* pA = new B();
B* pB = dynamic_cast<B*>(pA); // Checks if pA actually points to an instance of B
// ^^^^^^^^^^^^^^^^^^^^ at runtime, and returns nullptr if not
if(pB) {
// do stuff with B
}
The latter example requires you have a virtual base class:
class A {
public:
virtual ~A() {} // <<<<<<<<<<<<<<<<<<
};
If the object in question is not a polymorphic class it is possible to determine whether a class object pointed to has a specific base class at compile time. This sometimes occurs in template code where different base classes are possible.
You use std::is_base_of as follows: Note that you must also use std::remove_reference since *p is an lvalue and decltype() produces a reference.
#include <type_traits>
#include <iostream>
class A {};
class B : public A{};
int main() {
A a;
B b;
A* pa=&a;
B* pb=&b;
std::cout << std::is_base_of<A, B>::value << "\n"; // true
std::cout << std::is_base_of<B, A>::value << "\n"; // false
std::cout << std::is_base_of<A, std::remove_reference<decltype(*pb)>::type>::value << "\n"; // true
std::cout << std::is_base_of<B, std::remove_reference<decltype(*pa)>::type>::value << "\n"; // false
}
I have the following code
#include <iostream>
using namespace std;
class B{
int i;
public:
B(){
cout << "Constructing B\n";
}
void print(){
cout << "Printing from B with size : "<<sizeof(*this)<<endl;
}
};
class D:public B{
int i;
public:
D(){
cout << "Constructing D\n";
}
void print(){
cout << "Printing from D with size : "<<sizeof(*this)<<endl;
}
};
int main(){
B b;
b.print();
D d;
d.print();
D* dp;
dp->print();
}
Which gives me following output:
Constructing B
Printing from B with size : 4
Constructing B
Constructing D
Printing from D with size : 8
Printing from D with size : 8
So is it true that while you create a pointer to derived class it doesn't create the instance of a base class first? I don't think its true though because the size of D class is the proof. But its not even calling the base class constructor. Can anyone explain this?
Pointers do not create anything. Pointers are just pointers - scalar objects that contain addresses. It is your responsibility to make your pointers to point to proper locations in memory.
In your example pointer dp is not initialized. You never made it to point anywhere, so it points nowhere. Your attempt to call dp->print() produces undefined behavior. End of story.
Right now your pointer isn't be initialized at all, so trying to use it gives undefined behavior. Try something like:
D *dp = new D;
dp->print();
delete dp;
Or to do it better, something like:
std::unique_ptr<D> dp = std::make_unique<D>();
dp->print();
...and the unique_ptr will automatically delete the D when it goes out of scope.
Note, however, that you've define print as a non-virtual function, so the function that's invoked will depend on the type of pointer (or reference) used, not the type of the object it refers to. In addition, you haven't defined a virtual dtor.
Therefore, if you were to do something like:
B *p = std::make_unique<D>();
p->print(); // would invoke B::print, even though the object is a D
...and when it went out of scope, it would be destroyed incorrectly so you'd get undefined behavior. To correct this, you want to change B to something like this:
class B{
int i;
public:
B(){
cout << "Constructing B\n";
}
virtual void print(){
cout << "Printing from B with size : "<<sizeof(*this)<<endl;
}
virtual ~B() = default;
};
When you do this, the answer is "yes"--when you create the derived object, it'll first invoke the ctor for the base class, then the ctor for the derived class. When the derived object is destroyed, that is reversed: first the dtor for the derived class will be invoked, then when it finishes the dtor for the base class will execute.
It is constructing the base class before the derived class. Your output reflects this. Look at this
//Constructs Base class
Constructing B
//Constructs Derived class
Constructing D
//Prints from derived
Printing from D with size : 8
The reason that your code prints Printing from D with size : 8 twice without calling the constructor is that your code never creates a second instance of D.
D* d;
^^^^ Declares a pointer to a D, Does not create a D!
When you call d->print(); it is undefined behavior as d does not point to an instance of D. Finally, your code prints a value determined at compile time (sizeof(D) is a compile time value) and does not touch the this pointer your code runs.
See the documentation for sizeof here.
You can assign a pointer of Base with a Derived object by using the powerful polymorphism. That is possible because Derived implements everything that Base contains. Thus, it is implicit that Derived underlying instantiates the Base during its own instantiation.
class Base
{
public:
Base()
{}
}
class Derived : public Base
{
public:
Derived()
{}
}
Derived *derived = new Derived();
Base *base = derived;
First, I'm Java coder and want to understand polymorphism in c++. I wrote the example for learning purposes:
#include<iostream>
using namespace std;
class A
{
public:
virtual void foo(){ std::cout << "foo" << std::endl; }
};
class B : public A
{
public:
void foo(){ std::cout << "overriden foo" << std::endl; }
};
A c = B();
int main(){ c.foo(); } //prints foo, not overriden foo
I expected that overriden foo would be printed, but it wasn't. Why? We overrode the method foo in the class B and I thought that the decision which method should be called is being making from the runtime type of the object which in my case is B, but not a static type (A in my case).
Live example is there
When you do this:
A c = B();
You're converting the B value into A. You don't want that.
You should make a B object and access it through an A pointer or reference to get polymorphic behaviour:
B b;
A& c = b;
In java, you have value semantics with types like int and float, and you have reference semantics with everything else.
That's not the case in C++: the type system is unified, and you get whichever of value or reference semantics that you ask for.
With the code you've written
A c = B()
you've told the compiler to create a new value of type B, and then convert it to a value of type A, storing the value in c. Conversion, in this case, means taking A data out of the new B instance you created it, and copying it into the new A instance stored in c.
You could do this instead:
B b;
A &c = b;
This still creates the value b, but now c is a reference to A, which means c will now refer to the B instance you created, rather than being a copy of its A part.
Now, this still creates b as a local variable, and the object stored in b gets destroyed as soon as b goes out of scope. If you wanted something more persistent, you'd need to use pointers; e.g. something like
shared_ptr<A> c = make_shared<B>();
c->foo();
You could do something more 'raw' like
A *b = new B();
but this is a 'dumb' pointer; shared_ptr is smarter and your object will get destroyed when nothing else references it. If you do the latter, you'd have to do the destruction yourself when appropriate (and messing this up is a common source of mistakes)
Your confusion stems from a crucial difference between Java and C++.
In Java if you write
MyClass var = whatever;
your variable var is a reference to the object returned by whatever. However, in C++ this syntax means "create a new object of type MyClass by passing the result of the expression whatever to an appropriate constructor, and copy the resulting object into the variable var.
In particular, your code creates a new object of type A, named c, and passes a temporary default-constructed object of type B to its copy constructor (because that's the only constructor that fits). Since the newly created object is of type A, not of type B, obviously A's method foo is called.
If you want to have a reference to an object, you have to explicitly request that in C++, by adding & to the type. However a reference to non-constant objects cannot be bound to temporaries. therefore you need to explicitly declare also the object you bind to (or alternatively, use a reference to a const object, and fix your foo member functions to be const, since they don't change the object anyway). So the simplest version of your code doing what you want would read:
// your original definitions of A and B assumed here
B b; // The object of type B
A& c = b; // c is now a *reference* to b
int main() { c.foo(); } // calls B::foo() thanks to polymorphism
However the better version would be const-correct, and then could use your original construction:
#include <iostream>
class A
{
public:
virtual void foo() const // note the additional const here!
{ std::cout << "foo" << std::endl; }
};
class B : public A
{
public:
void foo() const // and also const here
{ std::cout << "overridden foo" << std::endl; }
};
A const& c = B(); // Since we bind to a const reference,
// the lifetime of the temporary is extended to the
// lifetime of the reference
int main() { c.foo(); } //prints overridden foo
(note that I removed using namespace std; because it's a bad thing to do (and your code used explicit std:: anyway, so it's just redundant).
Note however, that C++ references are still different from Java references in that they cannot be reassigned; any assignment goes to the underlying object instead. For example:
#include <iostream>
class A { public: virtual void foo() const { std::cout << "I'm an A\n"; } };
class B: public A { public: void foo() const { std::cout << "I'm a B\n"; } };
class C: public A { public: void foo() const { std::cout << "I'm a C\n"; } };
B b;
C c;
int main()
{
A& ref = b; // bind reference ref to object b
ref.foo(); // outputs "I'm a B"
ref = c; // does *not* re-bind the reference to c, but calls A::operator= (which in this case is a no-op)
ref.foo(); // again outputs "I'm a B"
}
If you want to change the object you refer to, you'll have to use pointers:
// definitions of A, B and C as above
int main()
{
A* prt = &b; // pointer ptr points to b
prt->foo(); // outputs "I'm a B"
prt = &c; // reassign ptr to point to c
prt->foo(); // outputs "I'm a C"
}
The line of interest is this (using uniform initialization syntax instead):
A c = B{};
It is important to note that, when declared this way, c behaves like a value.
Your code constructs a local A named c out of an instance of B. This is called slicing: Any part of that B that isn't also part of an A has been "sliced" away, leaving only an A.
Giving a symbol reference semantics in C++ (called indirection) requires a different notation.
For example:
A &c = B{};
A d = B{}; // Casts the intermediate B instance to const A &,
// then copy-constructs an A
c.foo(); // calls B::foo because c points to a B through an A interface
d.foo(); // calls A::foo because d is only an instance of an A
Note that the lifetime of the intermediate B to which c points is automatically extended to the scope of c. On the other hand, the second intermediate B is destroyed after the construction of d has completed.
In C++, references are immutable (they cannot be changed after initialization). When used in an expression, it is as though the object (value) to which they are pointing were used instead:
A &c = B{};
c = A{}; // Calls the compiler-provided A::operator = (const A &)
// (a virtual assignment operator with this signature
// was not defined).
// This DOES NOT change where c points.
Pointers, on the other hand, can be changed:
A a{};
B b{};
A *cptr = &b;
cptr->foo(); // calls B::foo
cptr = &a;
cptr->foo(); // calls A::foo
exactly what orlp said. you should also learn to use pointers too (they are fun)
A* c = new B();
c->foo(); // overriden foo
delete c;
class A{
public:
virtual void foo() {cout << "A::foo" << endl;}
};
class B: public A{
public:
virtual void foo() {cout << "B::foo" << endl;}
};
int main(void){
A a;
B b;
A acast=(A)B;
A *apointer=&B;
acast.foo(); // A::foo
apointer->foo() //B::foo
return 0;
}
Why does the two prints behave differently?
A acast=(A)b; (assuming this is what you actually have) slices the object and uses the sliced object to copy-construct an A. It's equivalent to A acast=A(b);. acast is of dynamic and static type A - no longer a B. It's a completely new object.
A *apointer=&b;, by contrast, is a pointer to an object whose dynamic type is B. The original b object isn't modified, it's just referred to by a pointer to the base type. Since the dynamic type is B, the method foo from B is called (because it's virtual and that's how polymorphism works).
object slicing, A acast=(A)b; slices B
The first example is an explicit cast the the compiler understand the object to be of type A. In the second example you're just setting the pointer and the compiler still sees the object as being type B.