Bất chấp tất cả các lời kêu gọi tuyên bố một thành viên ảo là riêng tư, lập luận chỉ đơn giản là không có nước. Thông thường, việc ghi đè một hàm ảo của lớp dẫn xuất sẽ phải gọi phiên bản lớp cơ sở. Nó không thể nếu nó được khai báo private
:
class Base
{
private:
int m_data;
virtual void cleanup() { /*do something*/ }
protected:
Base(int idata): m_data (idata) {}
public:
int data() const { return m_data; }
void set_data (int ndata) { m_data = ndata; cleanup(); }
};
class Derived: public Base
{
private:
void cleanup() override
{
// do other stuff
Base::cleanup(); // nope, can't do it
}
public:
Derived (int idata): base(idata) {}
};
Bạn phải khai báo phương thức lớp cơ sởprotected
.
Sau đó, bạn phải chấp nhận việc chỉ ra thông qua một nhận xét rằng phương thức nên được ghi đè nhưng không được gọi.
class Base
{
...
protected:
// chained virtual function!
// call in your derived version but nowhere else.
// Use set_data instead
virtual void cleanup() { /* do something */ }
...
Vì vậy, hướng dẫn số 3 của Herb Sutter ... Nhưng dù sao con ngựa cũng đã ra khỏi chuồng.
Khi bạn khai báo điều gì đó, protected
bạn hoàn toàn tin tưởng người viết của bất kỳ lớp dẫn xuất nào hiểu và sử dụng đúng cách các phần tử bên trong được bảo vệ, giống như cách một friend
khai báo ngụ ý một sự tin cậy sâu sắc hơn choprivate
các thành viên.
Người dùng có hành vi xấu do vi phạm sự tin tưởng đó (ví dụ như bị gắn nhãn 'không biết gì' do không thèm đọc tài liệu của bạn) chỉ có mình họ là người phải chịu trách nhiệm.
Cập nhật : Tôi đã có một số phản hồi tuyên bố rằng bạn có thể "chuỗi" các triển khai chức năng ảo theo cách này bằng cách sử dụng các chức năng ảo riêng tư. Nếu vậy, tôi chắc chắn muốn xem nó.
Các trình biên dịch C ++ mà tôi sử dụng chắc chắn sẽ không cho phép triển khai lớp dẫn xuất gọi một triển khai lớp cơ sở riêng.
Nếu ủy ban C ++ nới lỏng "riêng tư" để cho phép truy cập cụ thể này, tôi sẽ dành tất cả cho các chức năng ảo riêng tư. Như hiện tại, chúng tôi vẫn được khuyên là nên khóa cửa chuồng sau khi con ngựa bị đánh cắp.