![](/img/trans.png)
[英]Virtual method VS std::function member variable in terms of performance
[英]virtual overloading vs `std::function` member?
我正處於一個班級,我們稱之為Generic
。 這個類有成員和屬性,我打算在std::vector<Generic>
或類似的地方使用它,處理這個類的幾個實例。
此外,我想專門化這個類,泛型和專用對象之間的唯一區別是私有方法,它不訪問類的任何成員(但由其他方法調用)。 我的第一個想法是簡單地將其聲明為virtual
並在專門的類中重載它,如下所示:
class Generic
{
// all other members and attributes
private:
virtual float specialFunc(float x) const =0;
};
class Specialized_one : public Generic
{
private:
virtual float specialFunc(float x) const{ return x;}
};
class Specialized_two : public Generic
{
private:
virtual float specialFunc(float x) const{ return 2*x; }
}
因此我想我必須使用std::vector<Generic*>
,並動態創建和銷毀對象。
一位朋友建議我為我的Generic
類使用std::function<>
屬性,並將specialFunc
作為參數提供給構造函數,但我不知道如何正確地執行它。
這兩種方法的優點和缺點是什么,還有其他(更好的)方法來做同樣的事情嗎? 我很好奇。
有關詳細信息,我實例化的每個對象的特化將在運行時確定,具體取決於用戶輸入。 我可能最終會得到很多這些對象(還不確定有多少),所以我想避免任何不必要的開銷。
首先,讓我們把性能拋到窗外。
如果你使用virtual
函數,正如你所說,你可能會得到很多具有相同接口的類:
class generic {
virtual f(float x);
};
class spec1 : public generic {
virtual f(float x);
};
class spec2 : public generic {
virtual f(float x);
};
使用std::function<void(float)>
作為成員將允許您避免所有特化:
class meaningful_class_name {
std::function<void(float)> f;
public:
meaningful_class_name(std::function<void(float)> const& p_f) : f(p_f) {}
};
實際上,如果這是你正在使用類的唯一的東西,你也可以刪除它,並在調用者級別使用std::function<void(float)>
。
std::function
優點:
1)更少的代碼(N個函數有1個類,而虛函數需要N個函數的N個類。我假設這個函數是類之間唯一不同的東西)。
2)更靈活(如果你願意,你可以通過捕獲保持狀態的lambda)。
3)如果您將類作為模板編寫,則可以根據需要將其用於各種函數簽名。
使用std::function
解決了你試圖用virtual
std::function
解決的任何問題,它似乎做得更好。 但是,我不打算斷言std::function
總是比幾個類中的一堆虛函數更好。 有時,這些功能必須是私有的和虛擬的,因為它們的實現與任何外部調用者無關,因此靈活性不是優勢。
std::function
缺點:
1)我正要寫出來,你不能訪問的私有成員generic
類,但后來我意識到,你可以修改std::function
的類本身與持有捕捉拉姆達this
。 根據你概述課程的方式,這應該不是問題,因為它似乎無視任何類型的內部狀態。
這兩種方法的優點和缺點是什么,還有其他(更好的)方法來做同樣的事情嗎?
我能看到的問題是“你希望如何定義你的課程?” (如,什么是公共界面?)
考慮創建一個這樣的API:
class Generic
{
// all other members and attributes
explicit Generic(std::function<float(float)> specialFunc);
};
現在,您可以無需關心地創建任何Generic
實例。 如果你不知道你將在specialFunc
放置什么,這是最好的選擇(“你不知道”意味着你的代碼的客戶可能在一個月內決定從那里的另一個庫中放置一個函數,一個相同的函數(“接收”) x,返回x“),訪問某個數據庫獲取值,將有狀態仿函數傳遞給函數或其他任何東西)。
此外,如果specialFunc可以為現有實例更改(即使用specialFunc
創建實例,使用它,更改specialFunc
,再次使用它等),您應該使用此變體。
此變體可能會被其他約束強加給您的代碼庫。 (例如,如果想避免使Generic
虛擬化,或者由於其他原因需要它是final
的)。
如果(另一方面)你的specialFunc
只能從有限數量的實現中選擇,並且客戶端代碼以后無法決定他們想要別的東西 - 即你只有相同的功能和價值加倍 - 就像在你的例子中 - 然后你應該依賴於專業化,比如問題中的代碼。
TLDR :根據班級的使用情況決定。
編輯 :關於beter(或至少是替代)的方法...你可以在“按需”的基礎上在你的類中注入specialFunc:
也就是說,而不是這個:
class Generic
{
public:
Generic(std::function<float(float> f) : specialFunc{f} {}
void fancy_computation2() { 2 * specialFunc(2.); }
void fancy_computation4() { 4 * specialFunc(4.); }
private:
std::function<float(float> specialFunc;
};
你可以這樣寫:
class Generic
{
public:
Generic() {}
void fancy_computation2(std::function<float(float> f) { 2 * f(2.); }
void fancy_computation4(std::function<float(float> f) { 4 * f(4.); }
private:
};
這為您提供了更多的靈活性(您可以使用單個實例使用不同的特殊功能),代價是更復雜的客戶端代碼。 這也可能是您不想要的靈活性(太多)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.