簡體   English   中英

純虛擬基礎方法在派生類中的專業化

[英]Specialization of pure virtual base method in derived class

我想知道是否存在一種通用的方式/模式,以使派生類在給定的基類中具有某種更為專門化的純虛擬方法版本。

class Base {
public:
    Base() = default;
    virtual ~Base() = 0;
    virtual void foo(int bar) = 0;
};
inline Base::~Base() {}

class Derived public Base {
public:
    Derived() = default;
    ~Derived() = default;
    void foo(int bar) override {/*...*/}
};

class SpecializedDerived : public Base {
public:
    SpecializedDerived() = default;
    ~SpecializedDerived() = default;
    void foo(int bar, double additionalParameter) override {/*...*/}
};

SpecializedDerived類中的重寫是不可能的,因為該方法的簽名與純虛擬Base類中的簽名不對應。

現在,有沒有一種方法可以實現上述設計? 是否存在實現“更專門的方法”的方法,因為存在類繼承,因此可以實現“更專門的類”?

在鍵入時,我認為我的願望更多是“ Dude,我只希望您提供某種iterate(.)函數!” 事情。

到目前為止,我想到的唯一想法是

class Base {
public:
    Base() = default;
    virtual ~Base() = 0;
    virtual void foo(int bar) = 0;
};
inline Base::~Base() {}

class SpecializedDerived : public Base {
public:
    SpecializedDerived(double addParam) : additionalParam_(addParam) {}
    ~SpecializedDerived() = default;
    void foo(int bar) override {
        iterate(bar, additionalParam_);
        return;
    }
private:
    double additionalParam_;
    void foo(int bar, double additionalParam) {/*...*/}
};

您可以做的以下內部函數調用實際上是多余的:

class SpecializedDerived : public Base {
public:
    SpecializedDerived(double addParam) : additionalParam_(addParam) {}
    ~SpecializedDerived() = default;
    void foo(int bar) override {/* code using additionalPara_ */}
private:
    double additionalParam_;
};

首先閱讀Wikipedia +協變 這個想法是孩子可以用接受更廣泛接口的功能覆蓋該功能。 該函數必須接受舊接口,但也可以對其進行擴展。 這樣做的目的不是破壞對基類有引用/指針的代碼的期望。

請注意,當前,C ++不支持矛盾,因此這只是一個學術討論。

您代碼中的覆蓋函數不接受對舊接口的調用,因此不算為矛盾。 覆蓋:

virtual void foo(int bar):

重寫:

void foo(int bar, double additionalParameter) override {/*...*/} };

正確的方法是在C ++中手動遵循矛盾原則。 這或多或少是您想要做的。 您需要覆蓋:

void foo(int bar) override

並使其具有附加參數來調用該函數。 對於類的用戶來說,這似乎是矛盾(帶有附加的默認參數)。

注意:用常規函數重載虛擬函數是危險的,並且可能導致問題。 重載函數會在父級中隱藏具有相似名稱的函數。 除非小心處理,否則可能導致混亂和錯誤。 override關鍵字使問題不那么嚴重,但仍然存在一些風險。

為什么需要matchnig簽名?

多態和虛擬函數背后的想法是,調用者不必知道有關其使用的對象的真實類的任何詳細信息:

例:

Base *my_object = find_dynamically_a_relevant_object (...);              
my_object->foo(10);   // could be a Derived or a SpecializedDerived

std::vector<Base*> container;  
...                   // somehow you populate the container with a mix of 
...                   // Derived AND SpecializedDerived objects 
for (auto x: container)
    x->foo(std::srand());  

這就是為什么簽名必須與基類中定義的簽名完全匹配的原因。

但是還可以使用其他簽名嗎?

現在,您可以很好地定義在以下三種情況下具有完全不同的簽名的重載foo()

  • 不會override :它是一個具有相同名稱的不同函數。 *僅當確定對象具有正確的類型時,才可以使用其附加參數調用重載的foo()。
  • 您將必須確保提供了帶有匹配簽名的替代(因為它是純虛擬的)。 例如,這可能只是調用您的重載,對附加參數使用一些任意值)

例:

class SpecializedDerived : public Base {
public:
    SpecializedDerived() = default;
    ~SpecializedDerived() = default;
    void foo(int bar) override { foo(bar, 0.0); }
    void foo(int bar, double additionalParameter)  {cout<<"specialized "<<bar<<" "<<additionalParameter<<endl;}
};

... // elsewhere, for example in main(): 

SpecializedDerived my_obj;  
my_obj.foo(10);  // use the override of the base
my_obj.foo(10, 37.2); // use the overload

// suppose that p is a Base* like in the first example
auto *q = dynamic_cast<SpecializedDerived*>(p); 
if (q)  // dynamic cast makes this nullptr if not the right type
    q->foo(10, 37.2); 
else cout << "Not specialized"<<endl; 

根據某些輔助數據覆蓋行為

現在,如果您想在嚴格多態的上下文中使用foo(),但仍具有一些(隱藏的)其他參數,則有幾種可能性,例如:

  • 您可以擴展基本簽名並添加具有默認值的其他(通常未使用)參數。 在大多數情況下,這是一個壞主意:如果新的派生類帶有另一個參數,該怎么辦?
  • 您可以在進行調用之前注入其他參數(可以按照自己的建議在構造時注入,也可以在需要時使用設置器更改值)。 適用於大多數情況。 唯一的風險是在調用foo()之前確保正確設置了附加參數
  • 您可以更改簽名以將包含所有實際參數的對象用作單個參數。 這需要一些額外的開銷,但是對於可變參數來說非常靈活。 唯一的事情是,該對象的類型也很可能也需要是多態的,在這種情況下,必須確保正確的參數類型用於正確的對象。 對我來說,這似乎超級有力,但超級有風險。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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