[英]Deriving an abstract class from concrete class
假設我們有一個具體的class Apple
。 (可以實例化Apple對象。)現在,有人來從Apple派生抽象class Peach
。 它是抽象的,因為它引入了新的純虛函數。 現在,Peach的用戶被迫從中派生並定義此新功能。 這是常見的模式嗎? 這是正確的嗎?
樣品:
現在,我們有一個具體的class Apple { public: virtual void MakePie(); // more stuff here };
class Peach : public Apple { public: virtual void MakeDeliciousDesserts() = 0; // more stuff here };
class Berry
。
有人從漿果派生了抽象class Tomato
。
它是抽象的,因為它會覆蓋Berry的虛擬功能之一,並使之成為純虛擬的。
Tomato的用戶必須重新實現Berry中先前定義的功能。
這是常見的模式嗎?
這是正確的嗎?
樣品:
注意:名稱是人為設計的,並且不反映任何實際代碼(希望如此)。 在撰寫這個問題時沒有任何成果受到損害。class Berry { public: virtual void EatYummyPie(); // more stuff here };
\n\n
class Tomato : public Berry { public: virtual void EatYummyPie() = 0; // more stuff here };
來自蘋果的Re Peach:
來自漿果的Re Tomato:
Juice()
-提出了一定的要求並做出了一定的承諾。 派生類的Juice()
必須沒有更多要求,也不會更少承諾。 然后,僅知道Berry的DerivedTomato IS-A Berry和代碼是安全的。 通過記錄DerivedTomatoes必須調用Berry::Juice()
,可能會滿足最后一個要求。 如果是這樣,請考慮改用Template Method:
class Tomato : public Berry
{
public:
void Juice()
{
PrepareJuice();
Berry::Juice();
}
virtual void PrepareJuice() = 0;
};
現在,極有可能番茄IS-A漿果違反了植物學的預期。 (例外是,如果派生類的PrepareJuice
的實現強加了Berry::Juice
施加的前提以外的其他前提)。
在我看來,這似乎表明設計不好。 如果您想從一個封閉的庫中獲取一個具體的定義並對其進行擴展,並從中分支出很多東西,可能會被強制執行,但是那時候我將認真考慮有關繼承封裝的准則。 ,您可能應該。
是的,我想得越多,這是一個非常糟糕的主意。
不一定是錯誤的 ,但肯定是臭的。 特別是如果您將水果放在陽光下太長時間。 (而且我認為我的牙醫不希望我吃水泥蘋果。)
雖然,我在這里看到的主要問題不是從具體類派生的抽象類,而是真正的繼承層次。
編輯:重新閱讀我看到這是兩個層次結構。 所有的水果東西使我感到困惑。
如果您使用具有繼承模型“ is-a”的推薦做法,則這種模式幾乎永遠不會出現。
一旦有了具體的類,您就可以說它實際上是您可以創建其實例的東西。 如果然后從中派生一個抽象類,則作為基類的屬性的某些東西對派生類而言並不正確,派生類中的klaxons應該是不正確的。
在您的示例中,桃子不是蘋果,因此不應衍生自它。 源自漿果的番茄也是如此。
我通常會在這里建議圍堵,但這似乎並不是一個好的模型,因為Apple不包含Peach。
在這種情況下,我將排除常見的接口-PieFilling或DessertItem。
有點不尋常,但是如果您還有基類的其他子類,並且抽象類的子類具有足夠的通用知識來證明抽象類的存在,例如:
class Concrete
{
public:
virtual void eat() {}
};
class Sub::public Concrete { // some concrete subclass
virtual void eat() {}
};
class Abstract:public Concrete // abstract subclass
{
public:
virtual void eat()=0;
// and some stuff common to Sub1 and Sub2
};
class Sub1:public Abstract {
void eat() {}
};
class Sub2:public Abstract {
void eat() {}
};
int main() {
Concrete *sub1=new Sub1(),*sub2=new Sub2();
sub1->eat();
sub2->eat();
return 0;
}
嗯...通過思考“什么.....”幾秒鍾,我得出一個結論,這並不常見...而且,我不會從蘋果中得到桃子,從漿果中得到番茄...你有更好的例子嗎?
您可以在C ++中做很多奇怪的事...我什至都不會想到其中的1%...
關於使用純虛擬機覆蓋虛擬機,您可能只是將其隱藏,這真是很奇怪。
如果您可以找到一個愚蠢的C ++編譯器來將該函數鏈接為虛函數,那么您將獲得運行時純虛函數調用...
我認為這只能針對駭客,我不知道到底是哪種駭客...
要回答您的第一個問題,您可以這樣做,因為Apple用戶(如果給出了派生自Peach的具體實例將不會有任何不同)。 並且該實例將不會知道它不是Apple(除非您沒有告訴我們有關Apple的一些虛擬功能的說明,這些虛擬功能將被覆蓋)。
我還無法想象用純虛函數覆蓋虛函數會多么有用-甚至合法嗎?
通常,您要遵循Scott Meyers的著作中的“使所有非葉類抽象化”項目。
無論如何,除了您描述的內容似乎是合法的-只是我看不到您經常需要它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.