2011-10-31 22 views
7

thể trùng lặp:
When should I use C++ private inheritance?Tần suất thừa kế C++ không công khai được sử dụng trong thực tế là bao nhiêu?

Tôi muốn thực hiện này cộng đồng wiki nhưng không thấy nút ... ai đó có thể thêm nó?

Tôi không thể nghĩ ra bất kỳ trường hợp nào tôi đã bắt nguồn từ một lớp theo cách không công khai và tôi không thể nhớ lại mã đang xem mà thực hiện điều này.

Tôi muốn nghe các ví dụ và mẫu thực tế ở nơi hữu ích.

+0

Bạn không thể đặt câu hỏi CW nữa. Nếu bạn muốn, bạn có thể gắn cờ các mod để làm điều đó cho bạn. – sbi

+0

Cũng trên lãnh thổ tương tự như http://stackoverflow.com/questions/2090661/protected-inheritance. Cả hai câu hỏi này đều cho thấy rằng có những trường hợp người ta sử dụng thừa kế không công khai, khá bảo vệ (không phải tôi đang nói bạn đang tấn công nó!). – AAT

Trả lời

6

Mileage của bạn có thể thay đổi ...

Câu trả lời cốt lõi sẽ là thừa kế không công khai là vô ích.

Cá nhân, tôi sử dụng nó trong một trong hai trường hợp:

  • Tôi muốn kích hoạt cơ sở Optimization rỗng nếu có thể (thường, trong mẫu mã với các vị từ này là tham số)
  • Tôi muốn để ghi đè một hàm virtual trong lớp

Trong cả hai trường hợp, tôi sử dụng thừa kế private vì bản thân kế thừa là chi tiết triển khai.

Tôi đã thấy mọi người sử dụng số private thừa kế tự do hơn và gần như có hệ thống thay vì bố cục khi viết trình bao bọc hoặc hành vi mở rộng. C++ không cung cấp cú pháp ủy nhiệm "dễ", vì vậy làm như vậy cho phép bạn viết using Base::method; để ngay lập tức cung cấp phương thức thay vì viết một cuộc gọi chuyển tiếp thích hợp (và tất cả các quá tải của nó). Tôi cho rằng đó là hình thức xấu, mặc dù nó tiết kiệm thời gian.

3

Nếu bạn đã chọn thừa kế để phát triển trình bao bọc, phần thừa kế riêng là cách để đi. Bạn không còn cần hoặc muốn truy cập vào các phương thức và các thành viên của lớp cơ sở của bạn từ bên ngoài lớp trình bao bọc của bạn.

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

class BWrap; 
class AWrap : private A 
{ 
public: 
    AWrap(); 
    void foo(BWrap b); 
}; 

//no longer want A::foo to be accessible by mistake here, so make it private 
2

Đôi khi kế thừa các lớp học được không có bất kỳ virtual chức năng hay một virtual destructor (ví dụ container STL), bạn có thể phải đi cho phi public thừa kế. ví dụ.

template<typename T> 
struct MyVector : private std::vector<T> 
{ ... }; 

này sẽ không cho phép, tay cầm (con trỏ hoặc tham chiếu) của cơ sở (vector<>) để có được giữ nguồn gốc class (MyVector<>):

vector<int> *p = new MyVector<int>; // compiler error 
... 
delete p; // undefined behavior: ~vector() is not 'virtual'! 

Kể từ khi chúng tôi nhận được lỗi biên dịch tại dòng đầu tiên bản thân , chúng tôi sẽ được lưu từ hành vi không xác định trong dòng tiếp theo.

+0

Nhưng tại sao bạn sử dụng quyền thừa kế riêng thay vì thành phần ở đây;)? –

+0

@MatthieuM., Mặc dù đó là vấn đề về hương vị, nhưng bố cục sẽ không cho phép các hoạt động như 'is_base_of <>'. :) – iammilind

+0

Tôi biết đã có một số thay đổi về quy tắc truy cập trong bối cảnh SFINAE trong C++ 11 ... Tôi không nghĩ rằng 'is_base_of' cho phép truy cập' public' vào kiến ​​thức rằng lớp cơ sở được sử dụng và ' khách hàng riêng tư luôn có thể truy vấn thành viên chính nó ... vậy việc sử dụng là gì? –

2

Nếu bạn bắt nguồn từ một lớp không có destructor ảo thì thừa kế công khai dẫn đến cơ hội người dùng của lớp có thể gọi xóa trên con trỏ tới cơ sở, dẫn đến hành vi không xác định.
Trong trường hợp như vậy, bạn nên sử dụng Quyền thừa kế riêng.

Ví dụ phổ biến nhất về điều này là lấy được tư nhân từ các vùng chứa STL không có trình phá hủy ảo.


C++FAQ có một ví dụ tuyệt vời của Inheritance cá nhân mà kéo dài đến nhiều kịch bản sống thực.

Sử dụng hợp pháp, lâu dài để thừa kế riêng là khi bạn muốn xây dựng một lớp Fred sử dụng mã trong lớp Wilma và mã từ lớp Wilma cần gọi hàm thành viên từ lớp mới của bạn, Fred . Trong trường hợp này, Fred gọi các phi ảo trong Wilma, và các cuộc gọi Wilma (thường là các virtual virtual) trong chính nó, được Fred ghi đè. Điều này sẽ khó thực hiện hơn nhiều với bố cục.

Mã số Ví dụ:

class Wilma { 
protected: 
    void fredCallsWilma() 
    { 
     std::cout << "Wilma::fredCallsWilma()\n"; 
     wilmaCallsFred(); 
    } 
    virtual void wilmaCallsFred() = 0; // A pure virtual function 
}; 

class Fred : private Wilma { 
public: 
    void barney() 
    { 
     std::cout << "Fred::barney()\n"; 
     Wilma::fredCallsWilma(); 
    } 
protected: 
    virtual void wilmaCallsFred() 
    { 
     std::cout << "Fred::wilmaCallsFred()\n"; 
    } 
}; 
2

Kể từ private thừa kế có như mình sử dụng duy nhất được biết thực hiện thừa kế, và vì điều này luôn luôn có thể được thực hiện bằng ngăn chặn để thay thế (đó là ít đơn giản để sử dụng, nhưng gói gọn rõ hơn về mối quan hệ), tôi muốn nói nó được sử dụng quá thường xuyên.

(Vì không ai nói với tôi những gì protected thừa kế có nghĩa là, chúng ta hãy giả định không ai biết nó là gì và giả vờ nó không tồn tại.)

+0

+1 cho đoạn mã trên thừa kế 'protected'.Đôi khi tôi tự hỏi nếu nó không được giới thiệu đơn giản chỉ vì lợi ích nhất quán (ví dụ, vì 'protected' cũng là một specifier truy cập). –

+0

Mặt hàng 24 trong "Đặc điểm C++" của Herb Sutter cung cấp ví dụ duy nhất tôi từng thấy về sự thừa kế được bảo vệ. – Gorpik

+0

@Matthieu: Tôi nghĩ rằng sự thừa kế 'bảo vệ' không thực sự được đưa vào ngôn ngữ. Thay vào đó, không ai bận tâm _removing_ nó. ':)' – sbi

0

ngoài công lập (hầu như luôn luôn tin) thừa kế được sử dụng khi kế thừa (chỉ) hành vi và không phải giao diện. Tôi đã sử dụng nó chủ yếu, nhưng không phải là độc quyền, trong mixin.

Đối với một cuộc thảo luận tốt về chủ đề này, bạn có thể muốn đọc Barton và Nackman (Khoa học và Kỹ thuật C++:. Giới thiệu với Advanced Kỹ thuật và ví dụ, ISBN 0-201-53393-6   Mặc dù tên, phần lớn của cuốn sách là áp dụng cho tất cả C++, không chỉ khoa học và kỹ thuật ứng dụng . Và mặc dù ngày của nó, nó vẫn đáng đọc.)

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