-1

I came across the following c++ code in an online test.

#include <iostream>

class A
{
public:
    A(int n = 2) : m_n(n) {}

public:
    int get_n() const { return m_n; }
    void set_n(int n) { m_n = n; }

private:
    int m_n;
};

class B
{
public:
    B(char c = 'a') : m_c(c) {}

public:
    char get_c() const { return m_c; }
    void set_c(char c) { m_c = c; }

private:
    char m_c;
};

class C
    : virtual public A
    , public B
{ };

class D
    : virtual public A
    , public B
{ };

class E
    : public C
    , public D
{ };

int main()
{
    E e;
    C &c = e;
    D &d = e;
    std::cout << c.get_c() << d.get_n();

    c.set_n(3);
    d.set_c('b');
    std::cout << c.get_c() << d.get_n() << std::endl;

    return 0;
}

The code outputs a2a3 but I don't get it. Why does this run at the first place isn't the class B methods ambiguous? Also class E is not virtually inherited.

Cœur
  • 37,241
  • 25
  • 195
  • 267
4rcher
  • 49
  • 4

3 Answers3

5

If you were to try e.get_c(), that would be ambiguous.

However, the C and D interfaces only contain one B each, and know nothing about each other.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
3

Since c has type C& and d has type D&, there's no ambiguity - both C and D have exactly one B subobject.

(c and d literally refer to the respective subobjects of e - they don't refer to "e, but under a different type".)

The reason that the output is "a2a3" and not "a2b3" or "a2a2" is that A is inherited virtually, so there is only one A subobject in E and thus only one n member.

The C and D subobjects have one B subobject each, and d.set_c('b'); modifies the one in d but not the one in c.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
1

You are accssing methods of C and D classes via c and d references, there is no ambiguity. Try this

std::cout << e.C::get_c() << e.C::get_n() << std::endl;
std::cout << e.D::get_c() << e.D::get_n() << std::endl;

//line below will not compile because here access 'get_c' is ambiguous
//std::cout << e.get_c() << e.get_n() << std::endl;

here you will access methods of C and D classes directly via e instance. Now the last line is ambiguous because of call to e.get_c() and you have to specify either C:: or D:: prefix to resolve ambiguity on favor of C or D methods.

std::cout << e.C::get_c() << e.get_n() << std::endl;
std::cout << e.D::get_c() << e.get_n() << std::endl;

Note: there is no need to place prefixes before get_n() because A is a virtual base class, shered between both C and D in inheritance tree.

Pavlo Mur
  • 350
  • 3
  • 6