2010-09-03 54 views
1

我有兩個幾乎完全相同的類,除了一種方法。這些類具有相同的數據部分和除1之外的所有成員函數:C++中兩個真正類似的類只有一個不同的方法:如何實現?

class A { 
private: 
    double data; 
public: 
    double calc(){ 
    return data*data; 
    } 
    double especific(){ 
    return 2.0*data; 
    } 
} 

除了特定的方法之外,第二類是相同的。

該成員函數特別需要所有成員數據來計算,所以傳遞值或引用不是一個選項。有沒有很多代碼重複實現這個方法?只使用一個類或使用模板,但不使用繼承(巨大的性能影響)。

感謝

編輯:感謝所有的答覆。戰略模式可以幫助我,我會嘗試一下,看看它是否有效。基於我在不同程序中做過的一些測試,我避免了虛擬繼承作爲瘟疫。這個例程將被稱爲無處不在,性能是一個非常重要的因素。

+10

爲什麼你認爲繼承將是一個「巨大的性能影響」? – 2010-09-03 22:39:41

+0

我同意奧利查爾斯沃思。你有沒有運行一些性能工具來確定使用繼承會嚴重影響你的性能? – linuxuser27 2010-09-03 22:41:51

+7

除非您使用虛擬方法,否則繼承不會帶來任何開銷。 – doc 2010-09-03 22:47:28

回答

7

這聽起來像是Strategy pattern的工作。它可以在這種情況下作爲模板參數來實現。通常它將作爲類的構造函數參數或setter方法實現,但這需要繼承才能正常工作。

在這種情況下,像:

template <class SpecificStrategy> 
class A { 
private: 
    double data; 
public: 
    double calc(){ 
     return data*data; 
    } 
    double especific() { 
     return SpecificStrategy::especific(data); 
    } 
}; 

class DoubleStrategy { 
    static double especific(double data) { 
     return 2 * data; 
    } 
}; 
class TripleStrategy { 
    static double especific(double data) { 
     return 3 * data; 
    } 
}; 

然後,你可以參考一下:

A<DoubleStrategy> x; 
A<TripleStrategy> y; 

xy將是完全無關的類型,但它聽起來像那不是你想要的在這種情況下。

現在,在我看來,使用虛擬函數和繼承是最好的選擇。正如其他人指出的那樣,性能損失並不是那麼大。不過,在某些情況下,我可以看到這是一個壞主意。

例如,如果此類旨在表示圖形包中的矢量,並且您將對數百萬個圖形執行相同的轉換,那麼我可以看到如何不需要虛擬函數調用成爲進行轉換的代碼的一部分。事實上,你會希望避免任何形式的指針解引用都可以幫助它。

+4

好的答案;作爲一個方面說明,我經常會對那些將這種或那種技術標記爲「模式」的人發笑。模式被認爲是人的發明,還是他們被人看作是觀察者?因爲你稱之爲「戰略模式」,我稱之爲「功能性編程」。 – 2010-09-03 22:54:28

+1

@San Jancinto - 理想情況下,模式是觀察一個反覆出現的結構。 :-) – Omnifarious 2010-09-03 22:57:05

+0

@San Jacinto:通常情況下,模式只不過是一種複雜而過於複雜的方式,用命令式語言來近似函數式編程。 :) – jalf 2010-09-03 22:59:27

2

與所有常見的東西,一個基類,並從它

得出兩類正如其他人所指出的

一)這正是繼承是專爲

B)有沒有性能比較開銷任何

三)有沒有討厭的陷阱潛伏在任何地方

很多人將共同對此,說'啊,但xxxx怎麼樣';這些將是對高級和特殊情況使用的有效評論;除非你根據你所要求的簡單性不會做任何其中的任何一個。

+0

感謝您的回答,但我認爲我處於角落的情況。我只寫了一個(非常)簡化版本的問題。 – Ivan 2010-09-06 17:21:54

2

也許我錯過了點,但是爲什麼沒有實現所有的通用功能和純虛especific()一個基類,然後繼承這一點,並具有根據需要子類實現especific()。使data成員受到保護。

class BaseA 
{ 
protected: 
    double data; 
public: 
    double calc(){ 
    return data*data; 
    } 
    virtual double especific() = 0; 
}; 

class A1 : BaseA 
{ 
    double especific() 
    { 
    return data * 2; 
    } 
}; 

WRT繼承的巨大性能的影響......我認爲,除非虛函數表查找的成本與正在開展的工作方法體中進行,你在做這個比較是顯著,這是不太可能緊張的循環消耗了大部分應用程序處理。

+0

這正是我的情況:在一個被稱爲數百萬次的緊密循環中...... – Ivan 2010-09-06 17:21:08

0

我有一種感覺,Bridge pattern可能是一個很好的方法,因爲它聽起來像你想爲你的共同抽象有獨特的實現。

0

有幾種方法可以做到這一點,其中有許多您已經命名:從公共基類

  • 繼承(其中大部分工作的),和虛擬especific()
  • 一類,有兩個略有不同名稱的especific()方法(或重載方法)
  • 使用模板特
  • AB使用一些其他類C主要做工作的性質。

可能有其他的。

您需要根據您的類和應用程序的語義以及任何其他特定約束或要求來選擇其中之一。

1

退房的Strategy Pattern

你可以有你的類採取何種especific然後調用一個函數對象。您可以爲計算輸出的不同方法提供不同的函子。您還可以通過其他幾種方式實施戰略。

2

如果您沒有創建任何成員virtual並且智能地定義您的類,應該有沒有任何性能影響繼承

所有的繼承意味着「讓這個類像那樣,但是有了這些額外的東西」。它在運行時沒有什麼不同,如果你輸入了相同的東西兩次。

我想你可以使一個性能的影響,通過在子類不需要的父類的構造函數中做一堆unistcary的東西。但你不會那麼愚蠢。我相信你。

+0

感謝您的信仰! ;-)但是使用編譯時模板比使用繼承更快嗎? – Ivan 2010-09-06 17:19:27

+0

@伊萬 - 號爲什麼會這樣?生成的代碼沒有任何不同的理由。唯一真正的區別是模板可能需要更長的時間來編譯,而且更難以調試。 – 2010-09-07 12:44:55

2

爲什麼兩個班呢?如果這些類共享相同的數據,則可能只想在一個類中實現這兩個函數。

class A { 
private: 
    double data; 
public: 
    double calc(){ 
    return data*data; 
    } 
    double especific(){ 
    return 2.0*data; 
    } 
    double eMoreSpecific() { 
    return 23.0*data; 
} 
相關問題