2012-07-12 20 views
12
#include <iostream> 
struct B1 
{ 
    virtual void method()=0; 
    virtual ~B1(){} 
}; 

struct B2 
{ 
    virtual void method()=0; 
    virtual ~B2(){} 
}; 

struct D: B1, B2 
{ 
    virtual void method() 
    { 
     std::cout << "D::method\n"; 
    }; 
}; 

int main(int argc,char *argv[]) 
{ 
    D d; 
    B1 &b1=d; 
    B2 &b2=d; 
    b1.method(); 
    b2.method(); 
    return 0; 
} 

Lưu ý, B1 và ​​B2 không chia sẻ giao diện chung.Ghi đè chức năng ảo của các lớp cơ sở không có chung giao diện

Điều này có hợp pháp không? Nếu có - trong tiêu chuẩn nào? C++ 98/03/11?

Cả hai, msvc và gcc đã biên dịch OK.

Trước đây tôi nghĩ, rằng tôi phải sử dụng một số giao diện chung cho trường hợp này (có thể thừa kế ảo).

Tình huống như vậy có một số tên đặc biệt không?

Cách thức hoạt động chi tiết, vui lòng? Có lẽ một số tài liệu tham khảo ISO?

+0

Nếu bạn giải thích điều gì khiến bạn nghĩ rằng đó là trường hợp đặc biệt, ai đó có thể tìm thấy lời giải thích tốt. –

+0

Vì trong trường hợp đó, tôi mong đợi có hai hàm * thừa kế riêng biệt khác nhau trong phương thức D: B1 :: và phương thức B2 ::. – John

Trả lời

7

Mã của bạn được tốt được hình thành: void D::method() ghi đè cả void B1::method()void B2::method().

Trạng thái đặc tả (C++ 11 §10.3/2):

Nếu một hàm thành viên ảo vf được khai báo trong một lớp Base và trong một lớp học Derived, có nguồn gốc trực tiếp hoặc gián tiếp từ Base, một hàm thành viên vf có cùng tên, tham số kiểu-list , cv-qualification và ref-qualifier (hoặc vắng mặt) như Base::vf được khai báo, sau đó Derived::vf cũng là ảo (cho dù có khai báo hay không) và nó ghi đè Base::vf.

B1 tuyên bố chức năng thành viên ảo void B1::method(). Class D có nguồn gốc từ B1 và nó cũng tuyên bố một hàm thành viên có cùng tên (method), cùng một danh sách tham số (không có tham số), cùng cv-qualification (không đủ điều kiện) và cùng vòng loại (không đủ điều kiện).

Do đó, void D::method() ghi đè void B1::method().

Logic này cũng áp dụng cho void B2::method() (chỉ cần thay B2 cho B1 trong lời giải thích ở trên), vì vậy void D::method() ghi đè cả void B1::method()void B2::method().

+0

Cảm ơn bạn, điều đó nghe có vẻ đúng. Tôi đã tìm thấy các mục simmilar trên C++ 03 và C++ 98. Nhưng, tôi tò mò, có một số bổ sung trong tiêu chuẩn cho tình hình đó? Có lẽ một số ghi chú đặc biệt cho nhiều thừa kế? – John

+0

Ngoài "và ref-qualifier", tôi sẽ mong đợi các đặc điểm kỹ thuật là như nhau trong C++ 98 và C++ 03. –

+0

Tuyệt vời, đó là điều tốt để biết. Bằng cách này, chỉ * sử dụng * phương thức() * mà không cần * ghi đè lên nó chỉ được phép cho D nếu D được truy cập thông qua các tham chiếu lớp cơ sở/con trỏ. So sánh http://stackoverflow.com/questions/3310910/method-resolution-order-in-c/3310948#3310948 –

1

afaik điều này là hợp pháp trong mọi tiêu chuẩn. Tôi không chắc chắn nếu nó có tên riêng của nó, nhưng nó tương tự như diamond problem.

nếu bạn ghi đè "phương thức void ảo()" trong D, khi đó bạn ghi đè cả phương thức trong B1 và ​​B2.

Edit:

để anwser lý do tại sao bạn không có "hai independed khác nhau kế thừa chức năng ảo trong D: B1 :: phương pháp và B2 :: phương pháp":

khi trọng một phương pháp, bạn chỉ có thể chỉ định tên hàm, kiểu trả về và các tham số, nhưng bạn không thể thêm các chi tiết chữ ký về cái mà bạn kế thừa từ khi ghi đè.

tưởng tượng rằng nó sẽ có thể, sau đó nó có thể trông giống như thế này:

struct D: B1, B2 
{ 
    virtual void B1::method() 
    { 
     std::cout << "D::method\n"; 
    }; 
    virtual void B2::method() 
    { 
     std::cout << "D::method\n"; 
    }; 
}; 

nhưng nhìn thấy điều này, bạn đã có thể nói rằng không có khả năng để có một cái gì đó như thế, bởi vì khi gọi

objectD.method() 

bạn không thể chỉ định bạn đang gọi ai. vì vậy ngay cả khi có một cách để quá tải cả hai, vẫn còn có vấn đề phân biệt trên các cuộc gọi chức năng.

EDIT: "không thể chỉ định tên bạn đang gọi." đề cập đến, bạn không thể chỉ định liệu bạn có muốn gọi phương thức quá tải lớp D của phương thức B2 hay phương thức B2 hay không. phương pháp objectD.B2 :: phương pháp sẽ luôn luôn gọi B2 (không bị quá tải) (mà trong trường hợp này sẽ không biên dịch như B2 không có người thực hiện)

+0

Cảm ơn bạn, tôi đã hiểu điều này. Tôi muốn biết thêm một số chi tiết, bởi vì đó là một chút ngạc nhiên đối với tôi. – John

+0

@ James McNellis sẽ không chỉ có thể bên trong một thành viên lớp học? void B1method() {B1 :: method}? – cppanda

+1

kiểm tra http://ideone.com/jdsMI – John