2013-08-23 47 views
8

Tôi đã thử mã này:C++ kế thừa từ nhiều lớp cơ sở với tên hàm ảo cùng

class A 
{ 
    virtual void foo() = 0; 
}; 

class B 
{ 
    virtual void foo() = 0; 
}; 

class C : public A, public B 
{ 
    //virtual void A::foo(){} 
    //virtual void B::foo(){} 

    virtual void A::foo(); 
    virtual void B::foo(); 
}; 

void C::A::foo(){} 
void C::B::foo(){} 

int main() 
{ 
    C c; 
    return 0; 
} 

Nó là OK khi sử dụng phần bình luận, nhưng khi tôi cố gắng viết các định nghĩa bên ngoài khai báo lớp, các trình biên dịch báo cáo lỗi. Tôi đang sử dụng trình biên dịch MSVC11, có ai biết cách viết này không? Tôi cần chuyển mã vào tệp cpp.

Cảm ơn bạn ~~

+1

nhận xét cũng không hoạt động trong gcc. –

+2

Điều đó không có ý nghĩa gì cả. Nó chỉ nên là 'virtual void foo();', và chỉ * một lần *. –

+0

Bạn muốn _use_ 'A',' B' và 'C' như thế nào? Có nhiều khả năng: [ví dụ 1] (http://ideone.com/KlVTgv), [ví dụ 2] (http: // ideone.com/R2SyTz), ... (có thể xác định nhiều chức năng hơn mức cần thiết) –

Trả lời

4

Bạn đã có chỉ là một chức năng ảo foo:

class A { 
    virtual void foo() = 0; 
}; 

class B { 
    virtual void foo() = 0; 
}; 

class C : public A, public B { 
    virtual void foo(); 

}; 

void C::foo(){} 
void C::A::foo(){} 
void C::B::foo(){}; 

int main() { 
    C c; 
    return 0; 
} 
+3

* Chỉ là một chú thích: * Các định nghĩa 'void C :: A :: foo() {}' và 'void C :: B :: foo() {}' cung cấp các định nghĩa cho các hàm ảo thuần túy 'A :: foo 'và' B :: foo', tương ứng (và không bắt buộc). – dyp

+0

như nói ** dyp **: 'void C :: foo() {cout <<" C "<< endl;} void C :: A :: foo() {cout <<" A "<< endl ;} void C :: B :: foo() {cout << "B" << endl;}; int main() { C c; c.foo(); ((A &) c) .foo(); ((B &) c) .foo(); trả lại 0; } '** luôn luôn xuất 'C' ** – biv

+0

@dyp Chỉ cần tò mò tại sao nó hợp pháp để sử dụng cú pháp' void C :: A :: foo() {} 'để cung cấp định nghĩa cho 'A :: foo()', bất kỳ lợi ích nào để sử dụng loại cú pháp này thay vì ghi đè trực tiếp 'A :: for() {}'? Có vẻ rất khó hiểu với tôi, nếu 'A' là một lớp bên trong thì sao? Tôi biên soạn mã này và ngạc nhiên là nó hợp pháp. – Dreamer

15

Một chức năng ghi đè một hàm ảo của một lớp cơ sở dựa trên tên và thông số các loại (xem dưới đây) . Do đó, lớp học của bạn Chai chức năng ảo foo, một được kế thừa từ mỗi AB. Nhưng một hàm void C::foo() ghi đè cả:

[class.virtual]/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 , chức năng thành viên vf có cùng tên, thông số-loại-danh sách, 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) ed) và nó ghi đèBase::vf.

Như tôi đã nêu trong các ý kiến, [dcl.meaning]/1 cấm việc sử dụng một trình độ -id trong việc kê khai của một (thành viên) chức năng:

Khi declarator-id có đủ điều kiện, tuyên bố sẽ đề cập đến một thành viên khai báo trước của lớp hoặc namespace mà vòng loại đề cập [...]"

Do đó bất kỳ virtual void X::foo(); được illeg al như một tuyên bố bên trong C.

class C : public A, public B 
{ 
    virtual void foo(); 
}; 

là cách duy nhất để ghi đè AFAIK foo, và nó sẽ ghi đè lên cả A::fooB::foo. Không có cách nào để có hai ghi đè khác nhau cho A::fooB::foo với hành vi khác ngoài bằng cách giới thiệu một lớp thừa kế:

phần
#include <iostream> 

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

struct B 
{ 
    virtual void foo() = 0; 
}; 

struct CA : A 
{ 
    virtual void foo() { std::cout << "A" << std::endl; } 
}; 

struct CB : B 
{ 
    virtual void foo() { std::cout << "B" << std::endl; } 
}; 

struct C : CA, CB {}; 

int main() { 
    C c; 
    //c.foo(); // ambiguous 

    A& a = c; 
    a.foo(); 

    B& b = c; 
    b.foo(); 
} 
Các vấn đề liên quan