2015-05-15 21 views
10

xem xét mãNhiều thừa kế cơ sở nhập nhằng lớp

struct Base{}; 
struct Derived: public Base{}; 

struct A: public Base{}; 

struct B: public A, public Base{}; 

struct C: public A, public Derived{}; // why no ambiguity here? 

int main() {} 

Trình biên dịch (g ++ 5.1) cảnh báo rằng

cảnh báo: cơ sở trực tiếp 'Base' không thể tiếp cận trong 'B' do sự nhập nhằng struct B: public A, public Base{};

Tôi hiểu điều này, Base được nhân đôi trong B.

  1. Tại sao không có cảnh báo cho C? Không C được kế thừa từ cả hai số ADerived, cả hai đều được kế thừa từ Base?

  2. Tại sao thêm virtual

    struct Derived: virtual Base{}; 
    

kết quả bây giờ trong cả BC cảnh báo phát ra, sống trên Wandbox

cảnh báo: cơ sở trực tiếp 'Base' không thể tiếp cận trong 'B' do sự nhập nhằng struct B: public A, public Base{};

cảnh báo: cơ sở trực tiếp 'Base' không thể tiếp cận trong 'C' do sự nhập nhằng struct C: public A, public Derived{};

+0

Tìm kiếm Internet cho "thừa kế kim cương đáng sợ". –

+0

@ThomasMatthews Tôi biết vấn đề kim cương là gì và liên quan chặt chẽ đến lý do tại sao 'B' đưa ra cảnh báo. Tuy nhiên những gì tôi không hiểu là tại sao 'C' là OK. – vsoftco

+0

Tôi nghĩ rằng nó chỉ là một trường hợp của gcc không phát hiện sự mơ hồ trong 'C' vì' Base' * là * mơ hồ trong trường hợp đó quá.Khi bạn hầu như xuất phát từ 'Base', lớp dẫn xuất nhất (' C') chịu trách nhiệm gọi hàm tạo 'Base', và vì vậy gcc bắt đầu phát hiện sự mơ hồ một lần nữa. – Praetorian

Trả lời

2

Trong B, nó không thể đề cập đến các thành viên của Base subobject thừa hưởng trực tiếp. Hãy xem xét:

struct Base { 
    int x; 
}; 

struct B: public A, public Base { 
    void foo() { 
     int& x1 = A::x; // OK 
     int& x2 = x; // ambiguous 
     // no way to refer to the x in the direct base 
    } 
}; 

Trong C đây không phải là vấn đề. Cả hai x 's có thể được gọi bằng tên tiêu chuẩn:

struct C: public A, public Derived { 
    void foo() { 
     int& x1 = A::x; // OK 
     int& x2 = Derived::x; // OK 
    } 
}; 

Vì vậy, các cảnh báo bạn nhận được là một trong đó chỉ có ý nghĩa khi một cơ sở trực tiếp cũng được thừa hưởng thông qua con đường khác.

Đối với câu hỏi thứ hai của bạn, tôi không thể tạo lại cảnh báo bằng C trên Coliru bằng g ++ - 5.1.

2

Không có cách để truy cập một cách rõ ràng cho các thành viên cơ sở trong "B" trong khi nó có thể trong "C", như minh họa trong đoạn mã sau:

#include <iostream> 

using namespace std; 

struct Base 
{ 
    void print() 
    { 
     cout << "Base" << endl; 
    } 
}; 

struct Derived : public Base {}; 

struct A : public Base 
{ 
    void print() 
    { 
     cout << "A" << endl; 
    } 
}; 

struct B : public A, public Base 
{ 
    void print() 
    { 
     A::print(); 

     //error (ambiguous), no way to access to Base::print => warning 
     //Base::print(); 
    } 
}; 

struct C : public A, public Derived 
{ 
    void print() 
    { 
     A::print(); 
     Derived::print(); // Not Ambiguous, it's the Base inherited by 'Derived' which is used. 
     // Still an error but you can access print indirectly through "Derived" => no warning needed 
     //Base::print(); 
    } 
}; 

int main() 
{ 
    B b; 
    b.print(); 

    C c; 
    c.print(); 

    return 0; 
} 
Các vấn đề liên quan