I have the following code snippet:
#include <iostream>
#include <typeinfo>
using namespace std;
class A{
public:
int x;
A(int i = 0): x(i) {}
A minus(){
return 1 - x;
}
virtual void print(){
cout << x << "\n";
cout << "Base print\n";
}
};
class B: public A{
int y;
public:
B(int i = 0) {x = i;}
void print(){
cout << x << "\n";
cout << "Derived print!\n";
}
};
int main(){
A* p1 = new B(18);
*p1 = p1->minus();
p1->print();
return 0;
}
The output is:
-17
Derived print!
I know where -17 comes from. It does upcasting and A* p1 = new B(18) and makes p1 point to a derived object with x value of 18. *p1 = p1->minus make the object that p1 points to be an A(-17) /// cause 1 -18 = -17. My question is, where does the second line come from ? If p1 points to an A object after the *p1 = p1->minus(), why does p1->print() not print "Base print" ?
You created an object of the type class B
A* p1 = new B(18);
So the pointer p1 will point to this object until it (the pointer) will be reassigned.
In this statement
*p1 = p1->minus();
the dynamically created object of the type class B was not deleted. Only its sub-object of the type class A was changed using the implicitly defined by the compiler copy assignment operator of the class A and the pointer p1 still points to the same object of the type class B.
Thus in this statement
p1->print();
there is called the virtual function of the object of the type class B that by the way should be declared in the class B at least like
void print() override
{
//..
}
Pay attention to that you should declare a virtual destructor in the class A. For example
virtual ~A() = default;
And before exiting main you should delete the dynamically allocated object.
delete p1;
Related
I have the following code snipped:
#include <iostream>
#include <typeinfo>
using namespace std;
class B{
int i;
public:
B(){i = 1;}
virtual int get_i(){return i;}
};
class D: virtual public B{
int j;
public:
D(){j = 2;}
int get_i(){return B::get_i() + j;}
};
class D2: virtual public B{
int j2;
public:
int get_i(){return B::get_i() + j2;}
};
class MM: public D, public D2{
int x;
public:
MM(){
x = D::get_i() + D2::get_i();
}
int get_i(){return x;}
};
int main(){
B* o = new MM();
cout << o->get_i() << "\n";
MM* p = dynamic_cast<MM*>(o);
if(p) cout << p->get_i() << "\n";
D* p2 = dynamic_cast<D*>(o); /// Why does this dynamic_cast not return NULL?
if(p2)
cout << p2->get_i() << "\n";
}
The output will be:
My question is: Why does the dynamic_cast on the marked line success? So, if I have an hierarchy like:
class Grandpa{...};
class Dad : public Grandpa{...};
class Son: public Dad{...};
Of course that
Grandpa* grandpa = new Son();
Is ok.
Will the following dynamic_cast:
Dad* dad = dynamic_cast<Dad*>(grandpa);
always succeed ?
It's somehow logical, as long as a Dad pointer always can point to a Son object, but I have never seen this before, and I want to assure that I can take that as a general rule.
Why does the dynamic_cast on the marked line success?
Because the dynamic type of the object has a D base.
Will the following dynamic_cast:
Dad* dad = dynamic_cast<Dad*>(grandpa);
always succeed ?
Given the premise of Grandpa* grandpa = new Son();, yes it will succeed.
But it won't succeed in other cases such as for example:
Grandpa gp;
Grandpa* grandpa = &gp;
Dad* dad = dynamic_cast<Dad*>(grandpa); // is null
Yes, as long as the object pointed to by the superclass-type pointer really is an object of the type you are trying to cast to, dynamic_cast will succeed. If it isn’t an object of that type, otoh, dynamic_cast will return a null pointer.
This is modification of question and code presented in this link:
C++ multiple inheritance and vtables.
I understood from this link how vptr & vtable are setup.
My question is how does, bp->OutB() retrieves value of int a, which is member of classA.
I thought we pass this pointer to this method which looks at B part of class C.
Specifically,
Memory layout of classC assuming 32 bit.
&obj.
+0: vptr( pointer to virtual method table of classC( for classA).
+4: value of a.
+8: vptr( pointer to virtual method table of classC( for classB).
+12: value of b.
+16: value of c.
My questions is, we pass &obj+8 as this pointer to when we execute: bp->OutB(), but how does it end up retrieving member: int a of class A in that case.
#include <iostream>
using namespace std;
class A
{
public:
virtual void OutA() = 0;
int a;
};
class B
{
public:
virtual void OutB() = 0;
int b;
};
class C : public A, public B
{
void OutA();
void OutB();
int c;
};
void C::OutA()
{
cout << "Out A " << endl;
}
void C::OutB()
{
cout << "Out B " << " a is: " << a << endl;
}
int main()
{
C obj;
obj.a = 10;
obj.b = 20;
obj.c = 30;
obj.OutA();
obj.OutB();
A* ap = (A*)&obj;
B* bp = (B*)&obj;
ap->OutA();
bp->OutB();
return 0;
}
I have implemented the following piece of code
#include <iostream>
#include <memory>
class A
{
public:
int a;
virtual ~A()
{
}
};
class B : public A
{
public:
int b;
virtual ~B()
{
}
};
class E : public B
{
public:
~E()
{
}
};
class D
{
public:
operator std::shared_ptr<A>()
{
std::shared_ptr<A> pa = std::make_shared<A>();
pa->a = this->y;
return pa;
}
operator std::shared_ptr<B>()
{
std::shared_ptr<A> pb = std::make_shared<B>();
pb = *this;
(std::static_pointer_cast<B>(pb))->b = this->x;
return std::static_pointer_cast<B>(pb);
}
virtual ~D()
{
}
int x;
int y;
};
int main()
{
D d;
d.x = 6;
d.y = 7;
std::shared_ptr<E> pE = std::make_shared<E>();
std::shared_ptr<A> pa = pE;
std::shared_ptr<B> pB = std::dynamic_pointer_cast<B>(pa);
pB = d;
std::cout << "a " << pB->a << "b " << pB->b << std::endl;
return 0;
}
What I try to do is to convert the instance of class D, d, in a instance of shared pointer B which is derived from class A.
The B inherits the class A, and E inherits the class B.
When the program terminates, the program crashes in the destructor of class A.
I used GDB and see that this is NULL.
Does anyone have an idea why this happens?
Inside of D::operator std::shared_ptr<B>(), the use of std::static_pointer_cast<B>(pb) is undefined behavior, because pb does not point at an instance of B at that point, so it is illegal to cast the A pointer to a B pointer and access B's members. pb is pointing at the instance of A created by std::make_shared<A>() in D::operator std::shared_ptr<A>(). On the statement pb = *this;, you are discarding the B object you created and taking ownership of the A object that *this returns.
Thus, inside of main(), pB ends up pointing at an invalid B object and tries to destruct that object when main() exits, which is why you end up crashing the A destructor.
Had you used dynamic_pointer_cast instead of static_pointer_cast inside of D::operator std::shared_ptr<B>(), you would have ended up with a NULL pointer and likely crashed inside of D::operator std::shared_ptr<B>() when accessing B::b, instead of crashing in main().
You need to fix your operator std::shared_ptr<B>() to operate on a valid instance of B, not on an instance of A. For example:
operator std::shared_ptr<B>()
{
std::shared_ptr<B> pb = std::make_shared<B>();
std::shared_ptr<A> pa = *this;
*static_pointer_cast<A>(pb) = *pa; // <-- copy pa->a to pb->a ...
// or: simply do this instead:
// pb->a = pa->a;
pb->b = this->x;
return pb;
}
Consider the following code in which Base class constructor is initialized through Derived class constructor. When I am trying to access the Base class value x from main, it returns 0 instead of 5. What is wrong with my understanding?
#include <iostream>
using namespace std;
class Base
{
public:
int x;
Base() {}
Base(int a)
{
x = a;
}
};
class Der:public Base
{
public:
Der(int y) : Base(y)
{
x = y;
}
};
int main()
{
Base *ob1 = new Base();
Der *ob = new Der(5);
cout << ob1->x;
return 0;
}
When you call new Base(), you get an object from the default constructor. That happens to not initialise x at all, and so your code has undefined behaviour. You happen to see 0 this time, but that is not guaranteed.
When you call new Der(5), you get a different object, which uses the int constructor. In your case, setting x = y inside Der(int) is unnecessary, because you already called Base(y). The following line should output 5:
cout << ob->x;
Also note there is no reason to use dynamic allocation in this example. It's perfectly okay to use the stack:
int main()
{
Base base;
Der derived(5);
cout << "Base (undefined behaviour): " << base.x << endl;
cout << "Derived (defined): " << derived.x << endl;
return 0;
}
As I understand it, polymorphism with references should work exactly as it does with pointers.
However, consider the following example: the calls to doer() are correctly dispatched when using pointers, but the "B version" seems to be called in both case when using a reference.
I cannot figure out the reason why the following example is behaving in the way it does. Why is the "B version" called in both cases when using a reference?
#include <iostream>
class B;
class C;
void doer(B *x) {
std::cout << "B version" << std::endl;
}
void doer(C *x) {
std::cout << "C version" << std::endl;
}
class A {
public:
virtual ~A() {}
virtual void doit() = 0;
};
class B: public A {
public:
virtual void doit() override {
doer(this);
}
};
class C: public A {
public:
virtual void doit() override {
doer(this);
}
};
int main() {
B b;
C c;
A *a = &b;
a->doit(); // B version gets called, OK
a = &c;
a->doit(); // C version is called, OK
A &d = b;
d.doit(); // B version is called, OK
d = c;
d.doit(); // B version is called again??
}
Here you assign a reference:
A &d = b;
d.doit(); // B version is called, OK
Here you overwrite the object reffered to by d with c (it's no longer the definition of a reference):
d = c;
d.doit(); // B version is called again??
That's the main difference between references and pointers. A reference is like a constant pointer that you can only assign at definition. Afterwards, whenever you use the reference, it means the object you've referred to.
In fact when you do d = c; some slicing occurs. The object d is in fact a B, but the operator= from A is called, copying only member data of A.
Here how to demonstrate this statement:
class A {
public:
...
A& operator= (A a) {
cout << "A::operator=" << endl; // just to show what happens when d=c is called
return *this;
}
};
class B : public A {
public:
int x; // add some variables for B
virtual void doit() override {
cout << "B::doit() " << x << endl;
doer(this);
}
};
class C : public A {
public:
int a,b; // add aditional variables for C
virtual void doit() override {
cout << "C::doit() " << a << ","<<b << endl;
doer(this);
}
};
...
b.x = 123; // put some class specific variables in C
c.a = 222; c.b = 333; // put some class specific variables in C
A &d = b; // assignement of the reference. d reffers to a b object
d.doit(); // B version is called, OK
d = c; // but an A object is copied (so only A subobject of c is taken
// to overwrite A subobject of d)
d.doit(); // B version is called becaus again?? => yes !! because it's still a B
// And you see that the B part of the object is left intact by A::operator=
cout << typeid(d).name() << endl;
// remember at this point that d still refers to b !
References are bound by their referent for their entire lifetime, and, unlike pointers, require initialization. Using the assignment operator calls the assignment operator of the referent, and does not reassign the reference:
A &d = b;
d = c;
Here d = c calls the assignment operator from the base class A subobject contained in d, and copies the A subobject data contained in c.