0

I just want to get something straight because while I was learning about inheritance I noticed that I can inherit from an already derived class, and from the most derived class access the Base class's member directly. I think the following shows what I mean:

#include <iostream>

struct Base
{
    int member = 0;     // All members null
};

struct D1 : Base {};
struct D2 : Base {};
struct D3 : Base {};
struct D4 : Base {};

struct MostDerived : D1, D2, D3, D4 {};  // I know MostDerived now has 4 copies of Base


int main()
{
    MostDerived mostderived{};
    mostderived.D2::member = 2;                     // D2::Base::member = 2
    mostderived.D3::member = 3;                     // D3::Base::member = 3
    mostderived.D4::member = 4;                     // D4::Base::member = 4

    std::cout << mostderived.D1::member << '\n';        // Haven't touched D1, is still zero
    std::cout << mostderived.D1::Base::member << '\n';  // Equals 0, equivalent to above line
    std::cout << mostderived.Base::member << '\n';      // Read Base scope directly from most derived, equals zero

    mostderived.Base::member++;                         // Assign to member in Base scope directly from mostderived
                                                        // it now equals 1

    std::cout << mostderived.D1::member << '\n';        // But also does D1::member equal 1

    return 0;
}

So by doing mostderived.Base::member++ I changed the value of mostderived.D1::member. I'm just wondering if accessing Base like that makes any sense and why it particularly changed D1's copy of member. The way I'm picturing the layout is that MostDerived contains D1, D2, D3, D4, and each of those contain a Base, so it looks like the following.

enter image description here

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • Yeah I often hear to favour composition over inheritance, and my debugger actually shows derived classes as "containing" the base classes, so I suppose inheritance isn't so different from just popping the base class into the derived class definition, except that it comes with other features of course. – Zebrafish Aug 22 '17 at 15:00
  • The code doesn't build for me with `main.cpp:24:40: error: 'Base' is an ambiguous base of 'MostDerived' std::cout << mostderived.D1::Base::member << '\n';` – Post Self Aug 22 '17 at 15:01
  • @kim366 I see, that's interesting. I've only tried on my Visual Studio, so maybe it should be an ambiguous thing. Though I would have thought the ambiguous part would have been the mostderived.Base::member part – Zebrafish Aug 22 '17 at 15:05
  • Have a look at this explanation of regular vs virtual inheritance, it may clear things up a bit :) https://stackoverflow.com/a/2659142/7034621 – orhtej2 Aug 22 '17 at 15:10
  • @Zebrafish paste your code into here: http://coliru.stacked-crooked.com/ to see all errors in g++ – Post Self Aug 22 '17 at 15:13
  • I see, the error that makes sense to me is error: 'Base' is an ambiguous base of 'MostDerived', that definitely seems the case. I can't see any reason why modifying mostderived.Base::member would modify mostderived.D1::member, it just doesn't make sense. – Zebrafish Aug 22 '17 at 15:31

1 Answers1

1

So by doing mostderived.Base::member++ I changed the value of mostderived.D1::member.

If 'MostDerived' inherits from D1-4, then

mostderived.Base::member++;
                  ^

Is ambiguous.

Becouse 'MostDerived' has this hierarchy

int Base::member
int Base::member
int Base::member
int Base::member

and Base can be replaced with any of D1-4.


If you would use virtual inheritance

struct D1 : virtual Base {};
struct D2 : virtual Base {};
struct D3 : virtual Base {};
struct D4 : virtual Base {};

It would cause that 'MostDerived' would contain just one base class, so it wouldnt be ambiguous anymore to do

mostderived.Base::member++;

And it would be possible to access this member through all D1-4

mostderived.D1::member = 1;
mostderived.D4::member = 4;

of course since all D's share same variable, it would have same value for all, example:

MostDerived mostderived{};
mostderived.Base::member = 1;
std::cout << mostderived.D1::member << mostderived.D2::member << mostderived.D3::member << mostderived.D4::member;

Will print 1111.

kocica
  • 6,412
  • 2
  • 14
  • 35
  • As kim366 pointed out it doesn't compile on the online compiler linked. It definitely makes sense that it's ambiguous. I was running on Visual Studio. – Zebrafish Aug 22 '17 at 15:33
  • Do you have any other questions about this? :-) – kocica Aug 22 '17 at 15:36
  • No, I understand now that it's an ambiguous expression and probably a bug in my compiler. Thanks. – Zebrafish Aug 22 '17 at 15:41
  • I will soon edit my answer with `virtual` inheritance on this example you can take a look after. You are welcome. – kocica Aug 22 '17 at 15:42