Confusion about output of program with virtual inheritance - c++

I'm new to c++ and have been experimenting with virtual inheritance. But there is something that really confuses me.
#include <iostream>
using namespace std;
struct A {int m = 5005;};
struct B : A {};
struct C : virtual B {};
struct D : virtual B {int m = 6006;};
struct E : C, D {};
int main () {
E e;
e.m = 303;
cout << "e.A::m = " << e.A::m << endl;
cout << "e.D::m = " << e.D::m << endl;
cout << "e.m = " << e.m << endl;
}
The output of this is:
e.A::m = 5005
e.D::m = 303
e.m = 303
Now, what confuses me is e.D::m = 303. Shouldn't it be 6006? I know there are already quite a few questions to virtual inheritance but no one really explained why this is happening.
I also think I've found another program that shows the same "problem".
#include <iostream>
using namespace std;
struct S {int m = 101;};
struct A : virtual S {int m = 202;};
struct B : virtual S {int m = 303;};
struct C : virtual A, virtual B {int m = 404;};
struct D : C {};
struct E : virtual A, virtual B, D {};
int main () {
E e;
e.m = 10;
cout << "e.S::m = " << e.S::m << endl;
cout << "e.A::m = " << e.A::m << endl;
cout << "e.B::m = " << e.B::m << endl;
cout << "e.C::m = " << e.C::m << endl;
cout << "e.m = " << e.m << endl;
}
Where the output is
e.S::m = 101
e.A::m = 202
e.B::m = 303
e.C::m = 10
e.m = 10
And also here e.C::m=10 confuses me. Can someone please explain what's going on here? I acually thought I understood the principle of virtual inheritance.

I think the paragraph here explains this behavior:
Either way, when examining the bases from which the class is derived, the following rules, sometime referred to as dominance in virtual inheritance, are followed:
A lookup set is constructed, which consists of the declarations and
the subobjects in which these declarations were found.
Using-declarations are replaced by the members they represent and type
declarations, including injected-class-names are replaced by the types
they represent. If C is the class in whose scope the name was used, C
is examined first. If the list of declarations in C is empty, lookup
set is built for each of its direct bases Bi (recursively applying
these rules if Bi has its own bases). Once built, the lookup sets for
the direct bases are merged into the lookup set in C as follows
if the set of declarations in Bi is empty, it is discarded
if the lookup set of C built so far is empty, it is replaced by the lookup set of Bi
if every subobject in the lookup set of Bi is a base of at least one of
the subobjects already added to the lookup set of C, the lookup set of
Bi is discarded.
if every subobject already added to the lookup set of
C is a base of at least one subobject in the lookup set of Bi, then
the lookup set of C is discarded and replaced with the lookup set of
Bi
otherwise, if the declaration sets in Bi and in C are different,
the result is an ambiguous merge: the new lookup set of C has an
invalid declaration and a union of the subobjects ealier merged into C
and introduced from Bi. This invalid lookup set may not be an error if
it is discarded later.
otherwise, the new lookup set of C has the
shared declaration sets and the union of the subobjects ealier merged
into C and introduced from Bi
The example helps illustrate the logic here:
struct X { void f(); };
struct B1: virtual X { void f(); };
struct B2: virtual X {};
struct D : B1, B2 {
void foo() {
X::f(); // OK, calls X::f (qualified lookup)
f(); // OK, calls B1::f (unqualified lookup)
// C++11 rules: lookup set for f in D finds nothing, proceeds to bases
// lookup set for f in B1 finds B1::f, and is completed
// merge replaces the empty set, now lookup set for f in C has B1::f in B1
// lookup set for f in B2 finds nothing, proceeds to bases
// lookup for f in X finds X::f
// merge replaces the empty set, now lookup set for f in B2 has X::f in X
// merge into C finds that every subobject (X) in the lookup set in B2 is a base
// of every subobject (B1) already merged, so the B2 set is discareded
// C is left with just B1::f found in B1
// (if struct D : B2, B1 was used, then the last merge would *replace* C's
// so far merged X::f in X because every subobject already added to C (that is X)
// would be a base of at least one subobject in the new set (B1), the end
// result would be the same: lookup set in C holds just B1::f found in B1)
}
};
TL;DR: Because e.m = 303; is an unqualified lookup, the compiler will recursively look up the inheritance tree for matching declarations. In this case I think it would first find A::m, but would replace this with D::m after seeing that D has A as an indirect base class. So e.m ends up resolving to e.D::m.

I am answering you to your first question. You have just over write the value of m in your class D.
E e;
e.m = 303;//you just over write the value 6006, just comment out this line and check
cout << "e.A::m = " << e.A::m << endl;
cout << "e.D::m = " << e.D::m << endl;
cout << "e.m = " << e.m << endl;
Here B inherited A and B has been inherited to C and D virtually so only one copy of B will be available in E finally. So you can access data member m of class A through A::m and your e.m and e.D::m is accessing the same data member i.e. m of class D.
Now see below some interesting results:-
//e.m = 303;
cout << "e.A::m = " << e.A::m << endl;
cout << "e.D::m = " << e.D::m << endl;
cout << "e.m = " << e.m << endl;
e.m = 303;//over write D::m;
cout << "e.A::m = " << e.A::m << endl;
cout << "e.D::m = " << e.D::m << endl;
cout << "e.m = " << e.m << endl;
e.E::m = 101;//over write D::m
cout << "e.A::m = " << e.A::m << endl;
cout << "e.D::m = " << e.D::m << endl;
cout << "e.m = " << e.m << endl;
e.B::m = 202;//over write A::m through B
cout << "e.A::m = " << e.A::m << endl;
cout << "e.D::m = " << e.D::m << endl;
cout << "e.m = " << e.m << endl;

The virtual classes 'bubble up' to the top of the hierarchy, but they are considered after the non-virtual classes during lookup.
Example 1
struct E : C, D {}; becomes (virtual classes in round brackets):
E
C
D
(B) - bubbled up to E from other classes.
Next we look at what is in C and D:
E
C <-- continue lookup
(B) <-- will not continue to look for m here yet
D
(B) <-- will not continue to look for m here yet either
m <-- m found during unqualified lookup
(B) <-- may continue to look for m here, but already found it above
Example 2
struct E : virtual A, virtual B, D {}; becomes:
E
D - first non-virtual class at top level
(A)
(B)
(S) - bubbled up from other classes.
Next we look at what is in D:
E
D <-- continue lookup
C <-- continue lookup
m <-- m found during unqualified lookup
(A) <-- no further lookup, m already found
(B) <-- no further lookup, m already found
(S) <-- no further lookup, m already found

Related

Write a class that contains two class data members numBorn and numliving

This one the question from my assignment i can't understand what it's mean can anyone help me out with this please?
Write a class that contains two class data members numBorn and numliving. The value of numBorn should be equal to the number of object of the class that have been instanced. The value of numLiving should be equal to the total number of objects in existence currently(i.e the object that have been constructed but not yet destructed.)
You'll need to make your variables static data members of your class. Then your constructor(s) and destructor will increment and decrement as needed.
class A
{
public:
static std::size_t numBorn;
static std::size_t numLiving;
A()
{
++numBorn;
++numLiving;
}
~A()
{
--numLiving;
}
};
std::size_t A::numBorn = 0;
std::size_t A::numLiving = 0;
As a small demo
int main()
{
A a1;
A a2;
{
A a3;
std::cout << "living: " << A::numLiving << " born: " << A::numBorn << '\n';
}
std::cout << "living: " << A::numLiving << " born: " << A::numBorn << '\n';
}
will output
living: 3 born: 3
living: 2 born: 3
Note that when a3 falls out of scope, the numLiving is decremented from its destructor.

global variable changed by destructor not seen in result

I saw the following program on a site and I cannot understand the output .
http://codepad.org/T0qblfYg
#include <iostream>
using namespace std;
int i;
class A
{
public:
~A()
{
i=10;
}
};
int foo()
{
i=3;
A ob;
return i;
}
int main()
{
cout <<"\n 1) Before calling i is "<<i;
cout <<"\n 2) i = "<<i << " & the function return value = "
<< foo() << " and now i is " << i << endl;
return 0;
}
output is :
1) Before calling i is 0
2) i = 10 & the function return value = 3 and now i is 10
Now i is a global variable and destruction of A should have changed it to 10 before the call was returned to main. It is suggested that destruction of A happens after the call is returned to main but as a caller when i call a function i always expect the result to be final . Here the function return value is not 10 but 3 .
My question is why did i see this and where exactly is destruction getting called .
The order of evaluation is not what you would expect. When calling functions, the arguments to the functions can be evaluated in any order and even interleaved. So if you call
f( g(), h(), i() );
the order in which g(), h() and i() are called is up to the compiler. This also applies to operators. When you have an expression of the form
expr1 << expr2 << expr3 << expr4;
the order in which the expressions are evaluated is arbitrary. You only know, that the operator<< calls will be evaluated from left to right, because the operator is left-to right associative and you could rewrite the expression as
((expr1 << expr2) << expr3) << expr4;
The syntax tree looks like that:
<<
/ \
<< expr4
/ \
<< expr3
/ \
expr1 expr2
The leafs of the syntax tree can be evaluated in any order, even interleaved. And after all the leafs of an operator or function call are evaluated, the function itself will be called.
In your case foo() seems to get called before i gets printed out the first time and it is perfectly valid (though unexpected) behaviour.
Destructors run after the expression in the return statement is evaluated. If it was the other way around you'd be in deep trouble:
std::string f() {
std::string res = "abcd";
return res;
}
This function should return a string object that holds "abcd", not a copy of a string object that has already been destroyed.
why did i see this and where exactly is destruction getting called .
I believe the instance destructor is called when that instance goes out of scope. You might test it the following way (by controlling the scope of the instance -- see bar() below)
Note - to reduce confusion, I 1) renamed the global and 2) explicitly controlled when the foo or bar is called w.r.t. subsequent cout.
int g; // uninitialized!
class A
{
public:
~A()
{
g=10;
}
};
int foo()
{
g=3;
A ob;
return g;
} // <<<<<<<<<<< ob destructor called here
int bar()
{
g=3;
{
A ob;
} // <<<<<<<<<<< ob destructor called here
return g;
}
int t272(void)
{
g = 0; // force to 0
std::cout << "\n 1) Before calling foo g is " << g;
int fooRetVal = foo(); // control when called
// do not leave up to compiler
std::cout << "\n 2) after foo, g = " << g
<< "\n 3) fooRetVal = " << fooRetVal
<< "\n 4) and now g = " << g
<< std::endl;
g = 0; // force to 0
std::cout << "\n 1) Before calling bar g is " << g;
int barRetVal = bar(); // control when called
// do not leave up to compiler
std::cout << "\n 2) after bar, g = " << g
<< "\n 3) barRetVal = " << barRetVal
<< "\n 4) and now g = " << g
<< std::endl;
return (0);
}
With the output
1) Before calling foo g is 0
2) after foo, g = 10
3) fooRetVal = 3 <<< dtor called after return of foo
4) and now g = 10
1) Before calling bar g is 0
2) after bar, g = 10
3) barRetVal = 10 <<< dtor was called before return of bar
4) and now g = 10

Multiple Inheritance: Different Address same address

I have written a sample program.
If I print the address of pa and pb both are different.
Can you let me know why is this happening ?
#include<iostream>
using namespace std;
class A {
int x;
};
class B {
int y;
};
class C: public A, public B {
int z;
};
int main()
{
C c;
A *pa;
B *pb;
pa = &c;
pb = &c;
cout<<pa<<endl;
cout<<pb<<endl;
}
As Kerrek SB put it, pa and pb in your example don't actually point to c, but rather to the A and B subobjects of c.
With multiple inheritance, the data from the base classes is essentially stacked one after another. Base-typed pointers are simply offset to the data for that base class. Because of this, pa and pb point at different offsets into c.
#include<iostream>
using namespace std;
class A {
public:
int x;
};
class B {
public:
int y;
};
class C: public A, public B {
public:
int z;
};
int main()
{
C c;
cout << " &c: " << &c << endl << endl;
cout << "(A*)&c: " << (A*)&c << endl;
cout << "(B*)&c: " << (B*)&c << endl << endl;
cout << " &c.x: " << &c.x << endl;
cout << " &c.y: " << &c.y << endl;
cout << " &c.z: " << &c.z << endl << endl;
}
Result:
&c: 0x7ffdfeb26b20
(A*)&c: 0x7ffdfeb26b20
(B*)&c: 0x7ffdfeb26b24
&c.x: 0x7ffdfeb26b20
&c.y: 0x7ffdfeb26b24
&c.z: 0x7ffdfeb26b28
So you can see that C is laid out like this:
---------------
0x7ffdfeb26b20 | x | class A data
---------------
0x7ffdfeb26b24 | y | class B data
---------------
0x7ffdfeb26b28 | z | class C data
---------------
If you add some virtual methods to this example, you'll see that the same things happens with the subclass vtables.
--------- <------pa = &c
| x |
--------- <------pb = &c
| y |
---------
| z |
---------
it depends on the memory model of the class, above is an object of class C in memory
Back in the good old days of plain c, there were just structs.
struct Base{
int baseMember;
}
struct Child{
struct Base parent;
int someMoreMembers;
}
this way, dereferencing a pointer to a Child as if it were a base pointer, would result in a perfectly good pointer to the Base, because it is the first member.
In c++ this still works the same way (usually). But if you now inherit two classes, you cannot put them both as first member in your struct. So C++ converts a pointer to a base into a pointer to the child by adding the offset the specific base data is at.

Reference Behaviour in C++

Can I confirm with stackoverflow what I understand about reference in C++ is correct.
Let's say we have
vector<int> a;
// add some value in a
vector<int> b = a; // 1. this will result another exact copy of inclusive of a's item to be copied in b right?
vector<int> &c = a; // 2. c will reference a right? c and a both "point"/reference to a copy of vector list right?
vector<int> &d = c; // 3. d will reference c or/and a right? now a, c, d all reference to the same copy of variable
vector<int> e = d; // 4. e will copy a new set of list from d right (or you can say a or c)?
Thanks.
You're correct, b is a distinct copy of a, a/c/d are all the same thing, just accessible via different names.
And e is a copy of a/c/d.
If you duplicate that code using the int type rather than a vector, you can see by the addresses what's happening under the covers:
#include <iostream>
int main() {
int a = 7, b = a, &c = a, &d = a, e = d;
std::cout << "a # " << &a << '\n';
std::cout << "b # " << &b << '\n';
std::cout << "c # " << &c << '\n';
std::cout << "d # " << &d << '\n';
std::cout << "e # " << &e << '\n';
return 0;
}
The output of that is:
a # 0xbfaff524
b # 0xbfaff520
c # 0xbfaff524
d # 0xbfaff524
e # 0xbfaff51c
and you can see that a, c and d all have the same address while b and e are distinct.
Yep, looks right.
If you add elements to c or d, the new elements will also be reflected in a.
If you add elements to e, then only e will have them.

C++ slicing caused by reference

I have problem to understand the behavior of the following code, which I modified from an example for C++ slicing:
#include <stdio.h>
#include <iostream>
struct B {
int x;
B() { x = 0; }
virtual void foo( const char* id ) {
std::cout << id << ": B=" << this << ", x=" << x << std::endl;
}
};
struct D1 : B {
int y;
D1() { x = 1; y = 100; }
virtual void foo( const char* id ) {
std::cout << id << ": D1=" << this << ", x=" << x << ", y=" << y << std::endl;
}
} d1;
struct D2 : B {
int z;
D2() { x = 2; z = 200; }
virtual void foo( const char* id ) {
std::cout << id << ": D2=" << this << ", x=" << x << ", z=" << z << std::endl;
}
} d2;
void main() {
std::cout << "d1 = " << &d1 << std::endl;
std::cout << "d2 = " << &d2 << std::endl;
std::cout << "By pointer at beginning: " << std::endl;
B* pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
std::cout << "By Value: " << std::endl;
B b = d1;
b.foo( "d1" );
b = d2;
b.foo( "d2" );
std::cout << "By pointer after by value: " << std::endl;
pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
std::cout << "By reference: " << std::endl;
B& rb = d1;
rb.foo( "rd1" );
rb = d2;
rb.foo( "rd2" );
std::cout << "By pointer after by reference: " << std::endl;
pb = &d1;
pb->foo( "pd1" );
pb = &d2;
pb->foo( "pd2" );
}
//The result is the following:
d1 = 0115B504
d2 = 0115B510
By pointer at beginning:
pd1: D1=0115B504, x=1, y=100
pd2: D2=0115B510, x=2, z=200
By Value:
d1: B=0036FE44, x=1
d2: B=0036FE44, x=2
By pointer after by value:
pd1: D1=0115B504, x=1, y=100
pd2: D2=0115B510, x=2, z=200
By reference:
rd1: D1=0115B504, x=1, y=100
rd2: D1=0115B504, x=2, y=100
By pointer after by reference:
pd1: D1=0115B504, x=2, y=100
pd2: D2=0115B510, x=2, z=200
From the above result, we can see that:
Value assignment causes slicing problem to the assign destination (b) by dropping the derived specific members, but leave the assign sources (d1 and d2) intact.
Reference assignment causes slicing to the assign destination (rd) by not assigning the derived specific members, thus partially changes the assign sources (d1 and d2).
At first, I was surprised that you can assign a reference to a different type (D2 to D1) via their base, until I realize the infamous C++ casting system. One conclusion seems that reference can only be initialized but not assigned.
We know that STL container for base object has slice problem because except list, all other STL container copy object around. It looks that STL container for base references should fair no better, unless it saves pointers inside.
How do you guys deal with this problem?
Thanks!
CP
I'm finding it hard to find a question in your text, but I'm going to assume it is something like:
"How do I polymorphically store objects in a standard container?"
First, let me just say that you can't store references in standard containers because you can't assign (rebind) them.
So the normal way is to have a container of base class pointers. If the container owns the items, then use smart pointers like unique_ptr or shared_ptr. If the container does not own the objects, then just use raw pointers.
B& rb = d1;
rb.foo( "rd1" );
rb = d2;
The last line is equivalent as if you wrote
d1 = d2;
except it applies only to base class subobject. In the first line you set up the reference creating rb as alias to d1 with different static type. The reference can not be reseated. The later assign targets the object. d1 directly could only be assigned with using trickery with its op=, but your changed static type makes Base::op= work.
Many mentors say you should only use abstract classes as base, and most of the reasoning points to accidents like this.
In hierarchies you rarely have the op= left, if absolutely needed you have some virtual ssign thing that verifies compatibility.