[英]exposing only certain methods through public inheritence
我有一個基類,說Employee
有一些方法。 我稍后會派出一些子類,如Manager
, Developer
, Designer
等,這些子類也是員工(因為繼承)。 現在說代碼看起來像 -
#include <iostream>
#include <vector>
class Employee{
private : char name[5] = "abcd";
void allDept(){ std::cout<<"Woo"; }
public: void tellName(){std::cout << name << "\n"; }
void showEveryDept(){std::cout<< "Employee can see every dept\n";
allDept(); }
virtual ~Employee() {}
};
class Manager: public Employee{
private : char dept[5] = "aaaa";
public: void showOwnDept(){std::cout<< "Manager can see own dept\n";}
};
class Designer: public Employee{
private : char color = 'r';
public: void showOwnDept(){std::cout<< "Designer can see own dept\n";}
};
int main(){
Employee *E = new Designer;
E->showEveryDept();
// E->showOwnDept(); // will not work, but can be casted dynamically and even statically if sure, to call it!
Designer* D = dynamic_cast<Designer*>(E);
D->showOwnDept();
}
所以我們在這里看到的是我可以使用多態,將基類指針指向派生類對象,並仍在子類上調用基類可訪問方法。 另外,要從子類調用子類方法,我可以動態地將其轉換回來。
但是現在我想要做的是,從子類調用中隱藏一個公共類成員,這樣子類不能調用它,但是基類對象可以。 以showEveryDept()
為例,它可以由子類和父類調用。 但是由於Designer和Manager已經分配了他們的部門,我不希望他們訪問這個功能。
我嘗試了一種非常hacky的方法來解決這個問題,通過編寫另一層類的b / w Employee類和它的孩子,就像這樣 -
class Employee{
private : char name[5] = "abcd";
void allDept(){ std::cout<<"Woo"; }
public: void tellName(){std::cout << name << "\n"; }
void showEveryDept(){std::cout<< "Employee can see every dept\n";
allDept();}
virtual ~Employee() {}
};
class ELayer: private Employee{
private: using Employee::showEveryDept;
private: using Employee::tellName;
};
class Manager: public ELayer{
private : char dept[5] = "aaaa";
public: void showOwnDept(){std::cout<< "Manager can see own dept\n";}
};
class Designer: public ELayer{
private : char color = 'r';
public: void showOwnDept(){std::cout<< "Designer can see own dept\n";}
};
int main(){
Employee *E = new Designer;
E->showEveryDept();
// E->showOwnDept(); // will not work, but can be casted dynamically
// and even statically if sure, to call it!
Designer* D = dynamic_cast<Designer*>(E);
D->showOwnDept();
}
但是看起來很聰明,它不起作用 -
prog.cc: In function 'int main()': prog.cc:27:23: error: 'Employee' is an inaccessible base of 'Designer' Employee *E = new Designer;
那么我的選擇是什么? 一種愚蠢的方法是將該函數設置為虛擬,但是子類不會被強制覆蓋它,如果它們忘了聲明它,它會調用父函數嗎?
但是現在我想要做的是,從子類調用中隱藏一個公共類成員,這樣子類不能調用它,但是基類對象可以。
繼承基於Liskov替換原則 。 簡而言之,在任何我使用Base*
我應該能夠使用Derived*
並且一切都應該等效。 您希望通過使派生類的基類操作格式錯誤來違反該概念。 這意味着你的抽象是錯誤的。
而且,無論如何,這樣的事情毫無意義。 您無法動態實現此類機制,並且如果您靜態實現它,以便:
Derived d;
Base* b = &d;
b->foo(); // OK
d.foo(); // error
我總能做到:
static_cast<Base&>(d).foo(); // OK, just verbose
您可能需要層次結構的第二個分支:
struct Base { };
struct SpecialDerived : Base { void foo(); };
struct NormalDerived : Base { };
現在只有SpecialDerived
可以調用foo()
,但是每個SpecialDerived
仍然是一個Base
,每個NormalDerived
都是一個Base
,一切都運行得很順利。
聽起來像你可能需要重新考慮你的繼承層次結構。 如果派生自Employee
類不能調用showEveryDept()
,那么這表明showEveryDept()
不應該成為Employee
一部分。 通過嘗試從派生類中的Employee
公共接口中刪除方法,您將破壞子類型關系。 如果B
缺少使某些東西成為A
某些行為,則B
不是 A
而不應該從A
派生。
也許您應該添加另一個派生自Employee
類,並將showEveryDept()
移動到該類。 或者簡單地允許Manager
和Designer
調用showEveryDept()
是合適的行為。 如果不了解你的目標,我不能說。
另一種選擇是使用using
聲明的孩子,與私有繼承一起,選擇性地決定你可以訪問它。 這比virtual
替代方案更靈活,並且沒有任何額外開銷。 此外,它可以將公共訪問“轉換”為受保護的訪問。
class Employee
{
private:
char name[5] = "abcd";
void allDept()
{
std::cout << "Woo";
}
public:
void tellName()
{
std::cout << name << "\n";
}
void showEveryDept()
{
std::cout << "Employee can see every dept\n";
allDept();
}
virtual ~Employee() {}
};
class Designer : private Employee
{
private:
char color = 'r';
public:
using Employee::tellName();
void showOwnDept()
{
std::cout<< "Designer can see own dept\n";
}
};
現在,您可以調用Desginer::tellName()
和Designer::showOwnDept()
,但Designer::showEveryDept()
是私有的! 但是,缺點是您不能再從外部代碼將Designer*
轉換為Employee*
。 您可以在Employee
添加一個方法來做到這一點。 但是,您應該記得在派生類中using Employee::as_employee
。
class Employee
{
public:
Employee& as_employee()
{
return *this;
}
const Employee& as_employee() const
{
return *this;
}
};
無論如何,你應該問自己這是否真的是最好的預期設計,你真的需要這樣做,或者如果在Employee
中有一個(可選純的)虛擬函數showDept()
更好,派生類可能(或必須) ,如果純粹的覆蓋。
編輯 :從你的評論我讀到另一個答案,我可以很容易地得出結論,你的問題是你不明白基類, Employee
不會被用作某種“未分配的員工”占位符。 這樣:設計師是員工,未分配的員工是員工,但設計師不是未分配的員工。 因此,最好重新構建代碼。 無論如何,為了完整起見,我將離開上述解決方案。
在子女中隱藏父類(直接或間接)的方法並不是解決此問題的最佳方法。 例如,如果孩子的孩子想要獲得隱藏的功能怎么辦? 這是一團糟。
實現您所需要的一種方法是對其進行建模:員工是否能夠看到所有部門是員工的“屬性”。 因此,您可以添加bool屬性“CanShowEveryDept”,根據您的功能要求在父級中確定其默認值,並在每個子類構造函數中正確設置它。
class Employee
{
protected:
bool CanShowEveryDept;
public:
Employee()
{
CanShowEveryDept = true;
}
public:
void showEveryDept()
{
if (!CanShowEveryDept)
return;
std::cout << "Employee can see every dept\n";
allDept();
}
};
class Designer : private Employee
{
public:
Designer()
{
CanShowEveryDept = false;
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.