2012-12-18 37 views
18

Bạn có thể giải thích tại sao mã sau đây biên dịch và hoạt động tốt (được kiểm tra trên gcc-4.3.4). Tôi nghĩ rằng kế thừa chọn lọc không thể làm suy yếu hoặc thậm chí tăng cường quyền truy cập vào các thành viên/phương pháp. Nó không phá vỡ các quy tắc đóng gói?Thừa kế chọn lọc C++

#include <iostream> 

class A { 
protected: 
    void foo() { std::cout << "foo" << std::endl; } 
}; 

class B : private A { 
public: 
    using A::foo; //foo() becomes public?! 
}; 

int main() { 
    B b; 
    b.foo(); 
    return 0; 
} 
+0

+1 để dạy tôi điều gì đó. –

+1

Bạn thực hiện việc này khi kế thừa riêng tư từ các vùng chứa tiêu chuẩn. Về cơ bản, bạn cấm upcasting (điều này ngụ ý rằng bạn không cần một destructor ảo), nhưng bạn cho phép một số hoạt động mà sẽ là tẻ nhạt để reimplement/forward. –

Trả lời

12

Từ quan điểm ngôn ngữ, không có gì sai với điều này (dù thiết kế tốt là một vấn đề khác).

Mọi lớp học đều có thể chọn hiển thị cho những đối tượng rộng lớn hơn mà họ có quyền truy cập.

Về nguyên tắc, ví dụ của bạn là không có khác nhau để:

class B : private A { 
public: 
    void bar() { foo(); } 
}; 

ngoại trừ việc đây foo() được tiếp xúc bởi proxy.

Điều bạn không thể làm là ngược lại: lớp được dẫn xuất công khai không thể hạn chế quyền truy cập vào những thứ có thể truy cập được thông qua lớp cơ sở.

+1

Chắc chắn bạn có thể; trong 'struct A {int i; }; struct B: A {private: using A :: i; }; 'tên' B :: i' bí danh và bóng tối 'A :: i' với quyền truy cập riêng. Tất nhiên, điều đó không ngăn bạn viết 'b.A :: i', đó có lẽ là ý của bạn. – ecatmur

+1

@ecatmur: 'B' có thể làm xáo trộn mọi thứ, nhưng nó không thể hạn chế truy cập. Tôi luôn có thể upcast tham chiếu đến 'A &' và sử dụng 'A''s API:' A & a = b; a.i = 42; ' – NPE

+0

@ecatmur: Sự lựa chọn của tôi về từ * ẩn * là một chút không may. Tôi đã cải thiện từ ngữ. – NPE