[英]Implementing pure virtual function with common details for derived classes (c++)
[英]C++ Implementing a pure virtual function over a template
我正在嘗試在模板(TElementHolder)上實現抽象 class(ElementHolder)。 function virtual T* Fun2()
似乎工作正常,但 function virtual void Fun(T* element);
創建以下編譯錯誤:
source>:60:23: error: cannot declare variable 'fireHolder' to be of abstract type 'FireElementHolder'
60 | FireElementHolder fireHolder;
| ^~~~~~~~~~
<source>:51:7: note: because the following virtual functions are pure within 'FireElementHolder':
51 | class FireElementHolder : public TElementHolder<Fire>
| ^~~~~~~~~~~~~~~~~
<source>:22:22: note: 'virtual void ElementHolder::Fun(Element*)'
22 | virtual void Fun(Element* element) = 0;
|
有人可以向我解釋為什么這兩個函數會產生不同的結果嗎? 如果我能以某種方式完成這項工作?
我不確定在模板上實現純虛擬 function是否是正確的說法。
來源: https://godbolt.org/z/qEYdrYfYa
#include <iostream>
//------------------------------------------------------------------------------------------
class Element
{
public:
virtual ~Element() {}
virtual void Fun() = 0;
};
class Fire : public Element
{
public:
~Fire() {}
void Fun() { std::cout << "Fire" << std::endl; }
};
//------------------------------------------------------------------------------------------
class ElementHolder
{
public:
virtual ~ElementHolder() {}
virtual void Fun(Element* element) = 0;
virtual Element* Fun2() = 0;
};
template<class T>
class TElementHolder : public ElementHolder
{
public:
virtual ~TElementHolder();
virtual void Fun(T* element);
virtual T* Fun2();
};
template<class T>
TElementHolder<T>::~TElementHolder() {}
template<class T>
void TElementHolder<T>::Fun(T* element)
{
element->Fun();
}
template<class T>
T* TElementHolder<T>::Fun2()
{
std::cout << "Hello Fun2" << std::endl;
return new T();
}
class FireElementHolder : public TElementHolder<Fire>
{
};
//------------------------------------------------------------------------------------------
int main()
{
FireElementHolder fireHolder;
auto instance = fireHolder.Fun2();
fireHolder.Fun(instance);
instance->Fun();
}
這是工作代碼:
#include <iostream>
//------------------------------------------------------------------------------------------
class Element {
public:
virtual ~Element() = default;
virtual void Fun() = 0;
};
class Fire: public Element {
public:
~Fire() = default;
void Fun() { std::cout << "Fire" << std::endl; }
};
//------------------------------------------------------------------------------------------
class ElementHolder {
public:
virtual ~ElementHolder() = default;
virtual void Fun(Element* element) = 0;
virtual Element* Fun2() = 0;
};
template<class T>
class TElementHolder: public ElementHolder {
public:
virtual ~TElementHolder() = default;
virtual void Fun(Element* element) {
element->Fun();
}
virtual T* Fun2() override {
std::cout << "Hello Fun2" << std::endl;
return new T();
}
};
class FireElementHolder: public TElementHolder<Fire> {};
//------------------------------------------------------------------------------------------
int main() {
FireElementHolder fireHolder;
auto instance = fireHolder.Fun2();
fireHolder.Fun(instance);
instance->Fun();
}
一些亮點:
virtual void Fun(T* 元素)
必須更改為
虛空樂趣(元素*元素)
您的設計存在一個眾所周知的問題。
您有兩個並行的 class 層次結構Element
和ElelementHolder
。 您希望每個具體的ElementHolder
接受指向相應Element
的指針或引用。 因此,您將純虛擬 function 添加到基礎 class
class ElementHolder {
virtual void Fun(Element* element) = 0;
並在每個派生的 class 中覆蓋它(為了便於說明,我對您的層次結構進行了模板化,您的代碼中有一個T
而不是Fire
,但它並沒有真正影響任何東西):
class FireHolder : public ElementHolder {
virtual void Fun(Fire* fire) { ... }
這是一個非常自然和明智的選擇。
除了它根本不起作用,因為void Fun(Fire* fire)
不會覆蓋void Fun(Element* element)
。 它們是完全獨立的函數。
現在你如何解決這個問題? 有兩種非常不同的方式。
ElementHolder::Fun
。void Fun(Fire* fire)
更改為void Fun(Element* fire)
。 將fire
對Fire*
里面。 沒有ElementHolder::Fun
怎么辦? 簡單地說,就是不要調用它;)無論如何你都不能安全地使用它。 簽名Fun(Element*)
表示可以傳遞任何元素。 實際上,您只能將Fire*
傳遞給FireHolder
,而任何其他元素都是錯誤的(因此簽名存在——不是一個好主意)。 如果您只有一個ElementHolder
和一個Element *
,則無法保證您可以調用Fun
。
如果您絕對必須調用ElementHolder::Fun
,那么 #2 是您唯一的選擇。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.