2009-01-19 40 views
7

Hãy tưởng tượng một thừa kế kim cương tiêu chuẩn. Lớp A định nghĩa hàm fx ảo tinh khiết, lớp B định nghĩa việc triển khai thực hiện cho fx, các lớp C và D không làm gì với fx. Khi cố gắng gọi fx trên instance của lớp D, bạn sẽ nhận được lỗi 'call function ambiguous' mặc dù chỉ có một thực hiện fx. Điều này có thể được giải quyết bằng B và C kế thừa từ A theo cách ảo. Đây có phải là giải pháp chính xác cho sự cố không? Chính xác thừa kế ảo xử lý việc hợp nhất các bảng chức năng ảo như thế nào?Thừa kế kim cương và các chức năng ảo thuần túy

A ---> B ---> D

\ ---> C ------^

Trả lời

3

có phải là một giải pháp đúng cho vấn đề này?

Thừa kế "Kim cương" có vấn đề và giải thích đúng giải pháp mất một chút giải thích. Tôi khuyên bạn nên đọc các chương tiếp theo của Meyers' Effective C++:

  • mục 26, Bảo vệ chống tiềm năng mơ hồ
  • mục 43, Sử dụng đa kế thừa một cách sáng suốt.
19

... Lưu ý, Herb Sutter đã viết 3 bài viết tuyệt vời về nhiều thừa kế (1) here, (2) here(3) here. Anh ấy đã viết một loạt các bài viết hữu ích khác trong guru-of-the-week here. Rất khuyến khích ...

Trước tiên, tôi không chắc chắn rằng tôi có được quyền phân cấp của bạn. Tôi mang nó nó là như thế này:

struct A { 
    virtual void F() = 0; 
}; 

struct B : A { void F() { } }; 
struct C : A { }; 
struct D : B, C { }; 

Vâng, D là trừu tượng, vì có hai A subobjects trong một đối tượng kiểu D: Một là được làm bằng bê tông bởi B qua mạng của B, và một trong đó vẫn còn trừu tượng trong mạng thông qua C. Tôi lấy nó, bạn có một con trỏ đến D và thử gọi F. Vâng, một sự mơ hồ phát sinh, bởi vì trình biên dịch phát hiện hai chức năng F ở hai bờ chắn riêng biệt:

D -> B::F 
D -> C -> A::F 

Nhìn như thế này:

F() F() 
    A  A 
    |  | 
F() B  C 
     \ /
     D 

Bạn có thể sửa chữa tình hình đó chính thức bằng cách bắt nguồn từ A hầu như:

struct B : virtual A { void F() { } }; 
struct C : virtual A { }; 
struct D : B, C { }; 

Sau đó, bạn có tình huống này, được gọi là thừa kế kim cương:

 F() 
     A 
    / \ 
F() B  C 
     \ /
     D 

Và thực hiện tra cứu, nó thấy rằng có B::F ghi đè A::F. Mặc dù A::F vẫn có thể đạt được thông qua D::C::A, đó không phải là một sự mơ hồ nữa, bởi vì A được thừa hưởng ảo.

Cho dù đây có phải là giải pháp đúng trong vấn đề cụ thể của bạn hay không - đó là tất nhiên là không chắc chắn. Có những cách tốt nhất thường xuyên hơn là phát sinh ảo từ một lớp học. Đối với câu hỏi của bạn về việc hợp nhất các bảng chức năng ảo - điều đó hoàn toàn phụ thuộc vào việc thực hiện. GCC, theo như tôi biết, sẽ giữ một con trỏ đến một thể hiện trong bảng ảo D, nếu chúng tôi lấy được ảo.

+0

Cảm ơn. Đây là những gì tôi đã hỏi về. Nếu chức năng là trình biên dịch phụ thuộc vào việc triển khai thực hiện thì không có cách nào để đi. –

+0

hành vi là như nhau đối với mọi trình biên dịch - đó là cách trình biên dịch đạt được nó khác biệt. Bạn có thể tin tưởng các trình biên dịch rằng chúng hoạt động giống nhau, miễn là bạn không phụ thuộc vào một bố trí cụ thể của đối tượng (như, giá trị sizeof) sẽ phụ thuộc vào việc thực hiện. –

+0

Ok, hãy để tôi hỏi chính xác hơn: Nếu có thừa kế kim cương ảo và có một hàm được xác định trong cả A và B, nhưng không phải trong C, tôi có thể truy cập chức năng qua D không? Và cái nào sẽ là, cái được định nghĩa trong A hay cái từ B? Hành vi có phù hợp với tất cả các trình biên dịch không? –

Các vấn đề liên quan