簡體   English   中英

虛擬重載vs`std :: function`成員?

[英]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函數和重載模型是一種關系,而std::function模擬一個has-a關系。

使用哪一個取決於您的具體用例。

使用std::function可能更靈活,因為您可以在不引入新類型的情況下輕松修改功能。


性能不應該是這里的主要決策點,除非這個代碼可以證明(即你測量過)程序中的緊密循環瓶頸。

首先,讓我們把性能拋到窗外。

如果你使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM