2012-04-24 33 views
10

Tôi vừa thử đoạn mã này:Nhiều thừa kế: 2Classes1Method

struct FaceOfPast 
{ 
    virtual void Smile() = 0; 
}; 

struct FaceOfFuture 
{ 
    virtual void Smile() = 0; 
}; 

struct Janus : public FaceOfPast, public FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 

...

void main() 
{ 
    Janus* j = new Janus(); 
    FaceOfFuture* future = j; 
    FaceOfPast* past = j; 

    future->Smile(); 
    past->Smile(); 

    delete j; 
} 

Nó hoạt động như dự kiến ​​(kết quả đầu ra hai khuôn mặt cười), nhưng tôi không nghĩ rằng nó thậm chí nên biên dịch, việc khai báo lại số Smile() trong Janus không rõ ràng.

Làm thế nào (và tại sao) nó hoạt động?

Trả lời

7

Không có sự mơ hồ vì bạn gọi Smile() trên con trỏ tới FaceOfFutureFaceOfPast chỉ khai báo một phương thức Smile().

Bởi vì cách gọi phương thức trên một con trỏ lớp cơ sở không có thể dẫn đến một sự mơ hồ, chúng ta hãy đối xử với các tình huống khi bạn gọi phương thức trực tiếp trên con trỏ lớp con:

Janus* j = new Janus(); 
j->Smile(); 

Các lớp được thừa kế, bên cạnh việc ghi đè, cũng ẩn khai báo các lớp cơ sở là Smile(). Bạn muốn có một sự nhập nhằng chỉ khi bạn sẽ không được trọng dụng phương pháp trong lớp có nguồn gốc của mình:

Các biên dịch sau:

struct FaceOfPast 
{ 
    virtual void Smile() {printf(":) ");} 
}; 
struct FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 
struct Janus : public FaceOfPast, public FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 
int main() 
{ 
    Janus* j = new Janus(); 
    j->Smile(); 
} 

Mặc dù bạn gọi Smile trên Janus, tờ khai lớp cơ sở được ẩn .

Sau đây không:

struct FaceOfPast 
{ 
    virtual void Smile() {printf(":) ");} 
}; 

struct FaceOfFuture 
{ 
    virtual void Smile() {printf(":) ");} 
}; 

struct Janus : public FaceOfPast, public FaceOfFuture 
{ 
}; 

int main() 
{ 
    Janus* j = new Janus(); 
    j->Smile(); 
} 

Vì sự nhập nhằng.

+2

Câu hỏi dường như không phải về phần gọi, nhưng phần xác định lại: tại sao bạn có thể xác định lại 2 phương thức ảo có cùng tên từ 2 lớp khác nhau bằng cách chỉ viết một phương thức đơn? – alexisdm

0
Janus* j = new Janus(); 
FaceOfFuture* future = j; 
FaceOfPast* past = j; 

Đoạn mã này chuyển xuống lớp cơ sở. Vì vậy, khi bạn làm như sau

future->Smile(); 
past->Smile(); 

Đây thực sự là con trỏ đến FaceofPast và FaceOfFuture.

1

Theo tiêu chuẩn C++ (10.3.2):

Nếu một ảo chức năng thành viên vf được khai báo trong một lớp cơ sở và trong một lớp học nguồn gốc, có nguồn gốc trực tiếp hoặc gián tiếp từ cơ sở , chức năng thành viên vf có cùng tên, thông số kiểu danh sách, cv-qualification và ref-qualifier (hoặc vắng mặt) như Base :: vf được khai báo, sau đó Nguồn gốc :: vf [ ...] ghi đè Cơ sở :: vf.

Có dường như không có bất kỳ điều trị đặc biệt cho đa kế thừa, vì vậy nó có lẽ hầu hết áp dụng ở đây quá: void Janus::Smile() ghi đè cả hai phương pháp mà không cần bất kỳ sự mơ hồ, chỉ vì nó có cùng tên chính xác và chữ ký như cả lớp cơ sở phương pháp.