Virtual multiple inheritance and pointers - c++

Given the following class hierarchy:
class A {
int x;
public:
A(int X) : x(X) {}
void setX(int x) { this->x = x; }
};
class B : public virtual A {
int y;
public:
B(int X, int Y) : A(X), y(Y) {}
};
class C : public virtual A {
int z;
public:
C(int X, int Z) : A(X), z(Z) {}
};
class D : public C, public B {
public:
D(int x, int y, int z) : A(x), C(x,z), B(x,y) {}
};
and the following main:
int main (void)
{
D x(2,3,4);
A* temp1 = &x;
B* temp2 = &x;
C* temp3 = &x;
}
It seems that temp1,temp2 and temp3 are all pointing to different addresses..
Shouldn't B and C share the same A object?
After all, Every C and B object is ALSO an A so the pointers should "see" the A object first.. no?
In addition , the C pointer contains the X's address.. which is a D object. why?
here is the memory map:
&x 0x0036f828 {...} D *
temp1 0x0036f838 {x=5 } A *
temp2 0x0036f830 {y=3 } B *
temp3 0x0036f828 {z=4 } C *

It's just the way the object is represented in memory.
So your object looks like this:
+ 0x0036f828
- D
- int z (C)
- int y (B)
- int x (A)
C++ casting just gives the offset of the beginning of the object.
So you can see that the offset is just the size of an integer for classes A,B,C (because that's what they contain) and a virtual table for classes B,C.
And D doesn't have members, so its offset is 0.
Note that the C++ compiler sets the memory layout by the order you actually write the members and base classes.
So if you'd change the order of the base classes in D, then you'll get different results:
class D : public B, public C
Now B will be the first class in the layout after D.

You're right in that B and C needs to share the same A object. And that is exactly what would happen here. The address that you're seeing is actually the address of a virtual table that is unique to each class. In the case of virtual inheritance, the virtual table of each class would then have a pointer to the virtual base classes, in this case, object A.
So the virtual table of both classes B and C would have a pointer each pointing to the same address of object A.

This is how things might look if written out using plain structs:
struct A {
int x;
};
struct B {
A *ap;
int y;
};
struct C {
A *ap;
int z;
};
struct D {
C c;
B b;
A a;
};
int main (void)
{
D x;
A* temp1 = &x.a;
B* temp2 = &x.b;
C* temp3 = &x.c;
}
Since B and C use virtual inhertiance, they only contain a pointer to the base, and not the actual object. You can see that since c is at the beginning of D, they will have the same address.

Related

I cant understand this access modifier

I am the beginner of C++. And I have a programming test today. But I cant understand this examples.
class A
{
public:
int w;
};
class B : public A
{
public:
int x;
};
class C : private A
{
public: int y;
};
class D : protected B
{
public: int z;
};
int main()
{
D d;
d.w = 10; // compile error
}
I thought (D d; d.w = 10) is correct, but it has compile error.
D derived by B (protected), and B derived by A (public).
So, I think D can access A class member, because
Class B : public A
{ public:int x}
==>
Class B
{ public: int w; int x;}
and Class D : protected B
{ public: int z}
==>
class D
{public: int z; protected: int w, int x;}
Why I am wrong?? Thank you!
D can see members of A and B, but because of protected inheritance, only D and classes derived from D know that D is a B and can access B and A members. main is not derived from D, so main is not aware of D's inheritance of B and thus cannot access the inherited A and B members.

Issue in accessing member variables

#include<iostream>
class A {
int a, b;
public:
void setdata(int x, int y) { a = x; b = y; }
void showdata() { std::cout << a << b; }
};
class B : public A { };
int main() {
A a1;
B b1;
a1.setdata(5, 4);
a1.showdata();
b1.showdata();
}
I just want to print the values of the a and b members using the b1 object of class B, as it can access the member functions of class A since class B has public inheritance of class A. But, I am getting garbage values when I try to print the values of a and b using b1.
Can someone explain why this is happening and how to fix it?
a1 and b1 are completely separate object instances in memory. They have their own copies of the a and b members in memory. They have nothing to do with each other at all. Whatever you do to a1 does not affect b1 at all, and vice versa.
You are initializing the members of a1 only, you are not initializing the members of b1 at all. That is why you are seeing garbage when you try to print out the members of b1.
Before calling b1.showdata(), you need to call b1.setdata() to initialize b1's members, eg:
int main() {
A a1;
B b1;
a1.setdata(5, 4);
a1.showdata();
b1.setdata(1, 2); // <-- add this!
b1.showdata();
}
You should also give class A a default constructor that initializes the members to default values, in case setdata() is not called after construction (such as what happened in your case), eg:
class A {
int a, b;
public:
A() : a(0), b(0) {} // <-- add this!
void setdata(int x, int y) { a = x; b = y; }
void showdata() { std::cout << a << b; }
};
Alternatively, you might consider giving class A and class B a constructor that takes values as input, eg:
class A {
int a, b;
public:
A() : a(0), b(0) {}
A(int x, int y) : a(x), b(y) {} // <-- add this!
void setdata(int x, int y) { a = x; b = y; }
void showdata() { std::cout << a << b; }
};
class B : public A {
public:
B() : A() {}
B(int x, int y) : A(x, y) {}
};
/* or simpler:
class B : public A {
public:
using A::A; // <-- inherit all constructors
};
*/
int main() {
A a1(5, 4);
B b1(1, 2);
a1.showdata();
b1.showdata();
}

Virtual multiple inheritance

I stumbled upon this code example:
#include <iostream>
using namespace std;
class A {
int x;
public:
A() { x = 1; cout << "A"; }
};
class B : virtual public A {
int y;
public:
B() { y = 2; cout << "B"; }
};
class C : virtual public B, virtual public A {
int z;
public:
C() { z = 3; cout <<"C"; }
};
class D : public A, public B, public C {
int t;
public:
D() { t = 4; cout << "D"; }
};
int main()
{
D d;
return 0;
}
This code prints ABABCD and I have no idea why. I thought it would print A for D : public A, then AB for D : public B, then ABC for D : public C, and then D, but it seems A is only printed twice. How does this work?
The order of construction of the bases is (ignoring virtual bases) left to right as they are typed in the inheritance relationship. Once you add virtual bases, those are initialized first (before any non-virtual base) in a depth-first left-to-right manner.
Now this should explain the output.
D : A, B, C
A has no virtual bases, B has a virtual A base, so that is the first initialized: "A". Then C has a virtual B base, so that is the next one being initialized. At this point the A virtual subobject has already been initialized, so only the B constructor is evaluated "AB". At this point all virtual bases have been constructed and the non-virtual bases are constructed, first A, then B, then C, then the complete type D, yielding "ABABCD". The virtual sub objects have all been constructed, so they don't get constructed again.
Some things to keep in mind. A virtual base is only shared with other subobjects that are willing to share it (i.e. have it as a virtual base). There is no limit as of how many times a virtual base can be shared within a complete object (i.e. the A virtual base is shared multiple times, including from different B subobjects)

Junk values - Inheritance in C++

I have a class as follows:
class base
{
protected:
int x;
int y;
int z;
public:
base(int x, int y, int z)
{
x = x;
y = y;
z = z;
}
virtual void show();
};
I derive a class from the above as:
class derived : protected base
{
public:
int a;
int b;
int c;
derived(int a, int b, int x, int y, int z) : base(x, y, z) //initialising the base class members as well
{
cout<<a<<b<<x<<y<<z; //works fine
a = a;
b = b;
}
void show()
{
cout<<a<<b<<x<<y<<z; //show junk values
}
//some data members and member functions
};
In main(), I use:
derived d(1, 2, 3, 4, 5);
d.show();
The data members appear to have legal values inside the constructor. However, when I use a similar function, i.e. with the same visibility mode, junk values seem to appear.
a = a;
b = b;
should be
this->a = a;
this->b = b;
or, even better, use an initializer list:
derived(int a, int b, int x, int y, int z) : a(a), b(b), base(x,y,z)
{
cout<<a<<b<<x<<y<<z; //works fine
}
what you're doing is self-assigning the parameter, so the members don't get set.
You never initialize your member variables. a=a; will assign to the local variable a (the parameter), not the member variable. It should be this->a=a;. The same for the other members.

C++ referring to an object being constructed

In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing. So I'm trying to do something like this:
class A {
public:
A() : b(this) {}
private:
B b;
};
class B {
public:
B(A* _a) : a(_a) {}
private:
A* a;
};
Is there a way to ensure B always gets initialized with an A* without A holding a pointer to B?
Thanks
Try this:
class A;
class B {
public:
B(A *_a) : a(_a) {};
private:
A* a;
};
class A {
public:
A() : b(this) {};
private:
B b;
};
Since B is contained completely in A, it must be declared first. It needs a pointer to A, so you have to forward-declare A before you declare B.
This code compiles under more-or-less current versions of g++.
In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing.
You can store the pointer alright.
What you can't do is to try to get to the members/methods of A through the pointer in the constructor of B, since the parent instance might not be fully initialized at the point:
#include <iostream>
class Y;
class X
{
Y* y;
public:
X(Y* y);
};
class Y
{
X x;
int n;
public:
Y(): x(this), n(42) {}
int get_n() const { return n; }
};
X::X(Y* p): y(p)
{
//Now this is illegal:
//as it is, the n member has not been initialized yet for parent
//and hence get_n will return garbage
std::cout << p->get_n() << '\n';
}
int main()
{
Y y;
}
If you were to switch around the members in Y, so n would get initialized first, the constructor of X would print 42, but that is too fragile to depend on.