2011-08-26 24 views
6

Tôi đang bối rối là tại sao các trình biên dịch C++ sẽ không chấp nhận điều này:Tại sao trình biên dịch C++ không phân biệt giữa công khai được kế thừa và phương thức riêng được kế thừa có cùng tên?

class Foo { 
    private: void Baz() { } 
    }; 

    class Bar { 
    public: void Baz() { 
    }; 

    class FooBar : public Foo, public Bar { }; 

    void main() { 
    FooBar fb; 
    fb.Baz(); 
    } 

Các gcc lỗi cho là:

request for member ‘Baz’ is ambiguous 
candidates are: void Bar::Baz() 
       void Foo::Baz() 

nhưng không phải là nó rõ ràng rằng tôi muốn Bar :: Baz(), vì Foo :: Baz() là riêng tư? Tại sao trình biên dịch sẽ không định hướng ở đây?

Trả lời

7

Độ phân giải tên hoạt động theo hai giai đoạn. Đầu tiên tên được tra cứu rồi tên được chọn để truy cập. Nếu tên tra cứu là mơ hồ thì quyền truy cập sẽ không bao giờ được xem xét.

Vì sao, có thể đó là một thiết kế ngôn ngữ có chủ ý, nhưng tôi nghĩ nhiều khả năng nó chỉ đơn giản hóa quá trình giải quyết tên. Các quy tắc rất phức tạp.

+0

Đó là một chủ ý. Nó không làm cho trình biên dịch đơn giản hơn, ngược lại, nó hơi phức tạp hơn vì truy cập phải được kiểm tra như là một bước bổ sung. – curiousguy

3

Không rõ ràng - bạn có thể muốn gọi cho thành viên riêng tư (nếu có thể).

Chính thức, các quy tắc ngôn ngữ nói rằng tên được giải quyết trước và quá tải tốt nhất được chọn. Chỉ sau đó là có một kiểm tra khả năng tiếp cận.

1

Hạn chế truy cập không ảnh hưởng đến kế thừa. Bạn luôn kế thừa mọi thứ từ tất cả các lớp cơ sở. Trong trường hợp của bạn mà có vẻ không cần thiết, nhưng hãy xem xét một phiên bản sửa đổi một chút nơi hàm riêng là ảo:

class Base 
{ 
    virtual void secret_power() { /* innocent default */ } 
public: 
    void use_me() { secret_power(); } 
}; 

class Derived : public Base 
{ 
    virtual void secret_power() { /* overriding implementation here */ } 
}; 

Bây giờ cho bất kỳ Base& bạn luôn có thể gọi public interface phi ảo use_me(), nhưng các lớp thừa kế của bạn cung cấp thực hiện bằng phương tiện ảo riêng.

2

Để cho phép điều này, bạn cần cân nhắc xem bạn có ở trong ngữ cảnh cho phép bạn gọi phương thức riêng tư hay không. Nếu điều này được cho phép thì cuộc gọi:

fb.Baz() 

có thể có chức năng hoàn toàn khác nhau tùy thuộc vào việc bạn đang gọi nó từ ngữ cảnh công cộng hay riêng tư. Và điều đó không thực sự phù hợp với cách ngôn ngữ hoạt động.

+1

Đây là một điểm tuyệt vời. Cảm ơn! –

1

Như những người khác đã nói, đầu tiên tên được tra cứu, sau đó giới hạn truy cập được áp dụng. Bạn có thể giải quyết vấn đề này bằng cách gọi một cách rõ ràng phương thức bạn muốn, như trong

fb.Bar::Baz() 
+0

Nhưng hãy cẩn thận khi cú pháp đủ điều kiện nó làm hai việc: 1) kiểm soát tra cứu tên 2) vô hiệu hóa công văn động (không phải trong trường hợp cụ thể này, nhưng nó có thể). – curiousguy

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