Câu hỏi trong chủ đề cho thấy một sự nhầm lẫn khá phổ biến. Sự nhầm lẫn là đủ phổ biến, rằng Câu hỏi thường gặp về C ++ đã ủng hộ việc sử dụng ảo riêng trong một thời gian dài, bởi vì sự nhầm lẫn dường như là một điều xấu.
Vì vậy, để thoát khỏi sự nhầm lẫn trước tiên: Có, các hàm ảo riêng tư có thể được ghi đè trong các lớp dẫn xuất. Các phương thức của các lớp dẫn xuất không thể gọi các hàm ảo từ lớp cơ sở, nhưng chúng có thể cung cấp việc thực hiện riêng cho chúng. Theo Herb Sutter, việc có giao diện phi ảo công khai trong lớp cơ sở và triển khai riêng có thể được tùy chỉnh trong các lớp dẫn xuất, cho phép "tách biệt đặc tả giao diện khỏi đặc tả của hành vi tùy chỉnh của triển khai". Bạn có thể đọc thêm về nó trong bài viết "Ảo" của anh ấy .
Tuy nhiên, có một điều thú vị hơn trong mã bạn đã trình bày, theo tôi, đáng được chú ý hơn. Giao diện công cộng bao gồm một tập hợp các hàm không ảo quá tải và các hàm đó gọi các hàm ảo không công khai, không quá tải. Như thường lệ trong thế giới C ++, nó là một thành ngữ, nó có tên và tất nhiên nó rất hữu ích. Tên là (ngạc nhiên, ngạc nhiên!)
"Cuộc gọi không ảo quá tải công cộng được bảo vệ ảo không quá tải"
Nó giúp quản lý đúng quy tắc ẩn . Bạn có thể đọc thêm về nó ở đây , nhưng tôi sẽ cố gắng giải thích nó ngay.
Hãy tưởng tượng, các hàm ảo của Engine
lớp cũng là giao diện của nó và nó là một tập hợp các hàm quá tải không phải là ảo thuần túy. Nếu chúng là ảo thuần, người ta vẫn có thể gặp phải vấn đề tương tự, như được mô tả dưới đây, nhưng thấp hơn trong hệ thống phân cấp lớp.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Bây giờ, giả sử bạn muốn tạo một lớp dẫn xuất và bạn chỉ cần cung cấp một triển khai mới cho phương thức, lấy hai số nguyên làm đối số.
class MyTurbochargedV8 : public Engine
{
public:
// To prevent SetState( int var, bool val ) from the base class,
// from being hidden by the new implementation of the other overload (below),
// you have to put using declaration in the derived class
using Engine::SetState;
void SetState( int var, int val ) {/*new implementation*/}
};
Nếu bạn quên đặt khai báo sử dụng trong lớp dẫn xuất (hoặc để xác định lại tình trạng quá tải thứ hai), bạn có thể gặp rắc rối trong kịch bản dưới đây.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Nếu bạn không ngăn chặn sự che giấu của các Engine
thành viên, tuyên bố:
myV8->SetState(5, true);
sẽ gọi void SetState( int var, int val )
từ lớp dẫn xuất, chuyển đổi true
sang int
.
Nếu giao diện không phải là ảo và việc triển khai ảo không công khai, như trong sơ đồ của bạn, tác giả của lớp dẫn xuất có một vấn đề ít phải suy nghĩ và chỉ có thể viết
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};