簡體   English   中英

如何在C ++模板子類中部分重載虛函數?

[英]How can I partially overload a virtual function in a C++ template subclass?

我正在嘗試創建一個非模板基類來創建一個接口,通過該接口我可以與派生的模板類進行交互。 我希望使用部分虛函數重載,但有些東西不起作用,我不知道為什么。 任何人都可以解釋為什么我下面的代碼返回:

B match = False
D match = True
E match = False

而不是B,D返回True,E返回False? 我原以為派生類中的重載運算符會拾取指向int'&i'並被調用,但事實並非如此。

為了清楚起見,我不是試圖 - 覆蓋 - 匹配的基本版本,我正在嘗試-overload-它,特別希望它有一個不同的,在這種情況下比Base中的那個更專業的接口,使用其功能簽名時接管。

我也試圖避免為我可能實例化的Derived模板的每種風格擴展Base類。

更奇怪的是,我 - 可能 - 只是在這里瘋了,但我發誓這在不久前的某個時刻對我有用! Fwiw我在OSX 10.5上,使用llvm 7.0.0和clang 700.1.76。 這可能是編譯器的特性嗎?

雖然我在這里嘗試(不成功)使用部分重載,但我真的願意采用任何方法來解決通過其參數類型選擇模板實例函數的問題,而不會增加類,if-thens / case或者添加特定的Base類的特化。 如果您有其他方法可以用於類似功能,我很樂意聽到它。

感謝您提供的任何見解!

#include <stdio.h>

class Base
{
public:
  Base() {}
  virtual ~Base(){}

  virtual bool match( const void *data ) const { return false; }
};

template <class Type>
class Derived: public Base
{
public:
  Derived():Base() {}
  ~Derived() override{}

  virtual bool match( const Type *data ) const { return true; }
};

int main(int argc, char **argv)
{
  Derived<int>   *d = new Derived<int>();
  Derived<float> *e = new Derived<float>();
  Base *b           = d;

  int i;
  printf("B match = %s\n",b->match(&i)?"True":"False");
  printf("D match = %s\n",d->match(&i)?"True":"False");
  printf("E match = %s\n",e->match(&i)?"True":"False");

}

如果您要手動創建Derived<int>作為類,其成員函數將是:

virtual bool match( const int *data ) const { return true; }

它不會覆蓋基類。 因此,當您使用基類指針調用該函數時,它會執行基類實現,當您使用派生類指針調用它時,它會執行派生類實現。

如果使用override關鍵字,則可以在編譯時捕獲問題。

template <class Type>
class Derived: public Base
{
public:
  Derived():Base() {}
  ~Derived() override{}

  virtual bool match( const Type *data ) const override { return true; }
};

您應該看到該更改的編譯時錯誤。

請參閱http://ideone.com/8rBQ6B上的編譯器錯誤。

更新,以回應OP的評論

如果你不是要覆蓋:

  1. 不要在成員函數聲明中使用virtual
  2. 通過使用將基類函數放入派生類的范圍

     using Base::match 

    這是怎么做的:

     template <class Type> class Derived: public Base { public: Derived():Base() {} ~Derived() override{} using Base::match; bool match( const Type *data ) const { return true; } }; 

這里的問題是Derived::matchBase::matchBase::match 虛函數的函數簽名必須與工作機制相同。 因此,使用您的代碼Derived::match重載而不是覆蓋它。

如果我們改變

virtual bool match( const Type *data ) const { return true; }

virtual bool match( const void *data ) const { return true; }

然后我們得到

B match = True
D match = True

實例

因為函數的簽名不匹配:

class Base你有

virtual bool match( const void *data ) const { return false; }

請注意const void *參數類型

然后在Derived你有

virtual bool match( const Type *data ) const { return true; }

此實例中的Typeint (來自mainDerived<int> *d

只需在Base中添加一個帶有const int* data簽名的虛擬,然后就可以了。

是的,這確實意味着在Base你必須為你希望與Derived一起使用的每個Type添加一個match重載。

這不起作用的原因是因為派生類實際上並沒有覆蓋基類中的虛函數。 為了覆蓋基類中的虛函數,派生類必須具有完全相同的簽名(請參閱下面的注釋以了解異常)。 在這種情況下,簽名是不同的,因為基類中的虛函數采用void *但派生類中的函數采用type *

讓我們進行一個小的更改,並將override指令添加到派生類中的函數簽名:

#include <stdio.h>

class Base
{
public:
  Base() {}
  virtual ~Base(){}

  virtual bool match( const void *data ) const { return false; }
};

template <class Type>
class Derived: public Base
{
public:
  Derived():Base() {}
  ~Derived() override{}

  virtual bool match( const Type *data ) const override { return true; }
};

int main(int argc, char **argv)
{
  Derived<int> *d = new Derived<int>();
  Base *b         = d;

  int i;
  printf("B match = %s\n",b->match(&i)?"True":"False");
  printf("D match = %s\n",d->match(&i)?"True":"False");

}

這是我們現在編譯時會發生的事情:

main.cpp: In instantiation of 'class Derived<int>':
main.cpp:24:38:   required from here
main.cpp:19:16: error: 'bool Derived<Type>::match(const Type*) const [with Type = int]' marked 'override', but does not override
   virtual bool match( const Type *data ) const override { return true; }

假設我們正在使用C ++ 11,那么使用override來確保我們真的覆蓋基類虛函數總是一個好主意。

從上面注意:有一種稱為協變返回類型的東西,其中覆蓋不必具有相同的簽名,但這超出了問題的范圍。

感謝o_weisman在原始問題下的評論,我能夠找到一個使用函數模板的工作解決方案,(見下文)。 不可否認,在我的解決方案的當前形式中,我利用了一個限制,即Derived的每個Type-in​​stance都是一個單例。 這適用於我的特定設計,但可以根據需要擴展行為。 允許多個Derived實例的一種可能性是檢查Base :: match中的'this'指針是否在所有實例的集合中(在構造/銷毀時更新的靜態集變量中跟蹤),而不是反對單個單例實例。 無論如何,我希望這可以幫助那些可能面臨類似設計挑戰的人。

#include <stdio.h>
#include <assert.h>

template <class Type> class Derived;
class Base
{
public:
  Base() {}
  virtual ~Base(){}

  template <class Type>
  bool match( const Type *data ) const { return (Derived<Type>::instance() == this); }

};

template <class Type>
class Derived: public Base
{
public:
  Derived(): Base() { assert(!ourInstance); ourInstance = this; }
  ~Derived() override{}

  static const Base *instance() { return ourInstance; }

protected:
  static const Derived<Type> *ourInstance;

};

template <class Type>
const Derived<Type> *Derived<Type>::ourInstance = NULL;

int main(int argc, char **argv)
{
  Derived<int>   *d = new Derived<int>();
  Derived<float> *e = new Derived<float>();
  Base *b           = d;

  int i;
  printf("B match = %s\n",b->match(&i)?"True":"False");
  printf("D match = %s\n",d->match(&i)?"True":"False");
  printf("E match = %s\n",e->match(&i)?"True":"False");

}

這產生了以下期望的結果:

B match = True
D match = True
E match = False

暫無
暫無

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

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