2015-09-22 4 views
-1

Я наткнулся на следующий код C++ в онлайн-тесте.Несколько виртуальных наследований: почему метод класса не является неоднозначным?

#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; 
} 

Код выводит a2a3, но я не понимаю. Почему это выполняется на первом месте, а не методы класса B неоднозначны? Также класс E фактически не унаследован.

+0

Почему методы 'B' были бы двусмысленными? Он ничего не перегружает, так что у него нет никаких шансов быть двусмысленным? –

+0

Зачем вам нужно, чтобы 'E' был унаследован? Кем и зачем? –

+0

«_Also класс E практически не наследуется». Класс 'E' вообще не унаследован. – curiousguy

ответ

3

С c имеет тип C& и d имеет тип D&, нет никакой двусмысленности - как C и D имеют ровно один B субобъектом.

(c и d буквально относятся к соответствующим подобъектам e - они не относятся к «e, но под другим типом».)

причиной того, что выход «a2a3», а не " a2b3 "или" a2a2 "заключается в том, что A наследуется практически, поэтому существует только один подобъект A в E и, следовательно, только один член n.

В C и D подобъектов один B субобъектом каждый, и d.set_c('b'); изменяет один в d, но не один в c.

5

Если вы хотите попробовать e.get_c(), это будет неоднозначно.

Однако интерфейсы C и D содержат только один номер B и ничего не знают друг о друге.

1

Вы accssing методы C и D классов через c и d ссылки, нет никакой двусмысленности. Попробуйте

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; 

здесь вы получите доступ к методам C и D классов непосредственно через e инстанции. В настоящее время последняя строка неоднозначна из-за звонка e.get_c() и вы должны указать либо C::, либо D:: префикс для решения проблемы неопределенности в пользу C или D.

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

Примечание: нет необходимости размещать префиксы перед тем get_n(), потому что A является виртуальным базовым классом, shered между обоими C и D в дереве наследования.