![](/img/trans.png)
[英]Why does the base class pointer point to the pure virtual method in the base class instead of the overidden method in the derived class?
[英]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
關鍵字使問題不那么嚴重,但仍然存在一些風險。
多態和虛擬函數背后的想法是,調用者不必知道有關其使用的對象的真實類的任何詳細信息:
例:
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.