C++ 如何在C++;模板子类?

C++ 如何在C++;模板子类?,c++,templates,overloading,C++,Templates,Overloading,我试图创建一个非模板基类来创建一个接口,通过它我可以与派生模板类交互。我希望使用部分虚拟函数重载,但有些东西不起作用,我不知道为什么。 有人能解释我为什么返回以下代码吗: B match = False D match = True E match = False 而不是B,D返回True,E返回False?我本以为派生类中的重载运算符会拾取指向int'&I'的指针并被调用,但事实并非如此 明确地说,我不是试图覆盖match的基本版本,而是试图重载match,特别是希望它有一个不同的、在本例中

我试图创建一个非模板基类来创建一个接口,通过它我可以与派生模板类交互。我希望使用部分虚拟函数重载,但有些东西不起作用,我不知道为什么。 有人能解释我为什么返回以下代码吗:

B match = False
D match = True
E match = False
而不是B,D返回True,E返回False?我本以为派生类中的重载运算符会拾取指向int'&I'的指针并被调用,但事实并非如此

明确地说,我不是试图覆盖match的基本版本,而是试图重载match,特别是希望它有一个不同的、在本例中更专业的接口,而不是使用其函数签名时接管的Base中的接口

我还试图避免为可能实例化的每种派生模板扩展基类

甚至是陌生人,我可能会在这里发疯,但我发誓这在不久前的某个时候对我有用!Fwiw我在OSX 10.5上,使用llvm 7.0.0和clang 700.1.76。这可能是编译器的特性吗

虽然我尝试(未成功)在这里使用部分重载,但我非常愿意使用任何方法来解决按参数类型选择模板实例函数的问题,而不增加类(如果是s/case)或向基类添加特定的专门化。我很想听听你是否有其他方法,我可以顺便来看看类似的功能

感谢您提供的任何见解

#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");

}
#包括
阶级基础
{
公众:
Base(){}
虚拟~Base(){}
虚拟布尔匹配(const void*data)const{return false;}
};
模板
派生类:公共基
{
公众:
派生():基(){}
~Derived()重写{}
虚拟布尔匹配(常量类型*数据)常量{return true;}
};
int main(int argc,字符**argv)
{
派生*d=新派生();
派生*e=新派生();
基*b=d;
int i;
printf(“B match=%s\n”,B->match(&i)?“True”:“False”);
printf(“D匹配=%s\n”,D->match(&i)?“True”:“False”);
printf(“E match=%s\n”,E->match&i)?“True”:“False”);
}

这里的问题是
派生::匹配
基本::匹配
不匹配。虚拟函数的函数签名必须相同,才能使机制工作。因此,使用您的代码
Derived::match
重载,而不是覆盖它

如果我们改变

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

然后我们得到

B match = True
D match = True

如果要手动创建
派生的
类,其成员函数将是:

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; }
};
以下是如何做到这一点:

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

  using Base::match;
  bool match( const Type *data ) const { return true; }
};
模板
派生类:公共基
{
公众:
派生():基(){}
~Derived()重写{}
使用Base::match;
布尔匹配(常量类型*数据)常量{return true;}
};

因为函数的签名不匹配:

基本类中
您有

virtual bool match( const void *data ) const { return false; }
virtual bool match( const Type *data ) const { return true; }
注意
const void*
参数类型

然后在
派生的

virtual bool match( const void *data ) const { return false; }
virtual bool match( const Type *data ) const { return true; }
其中本例中的
Type
int
(来自
main
派生*d

只需添加一个带有
const int*data
signature的虚拟in Base,就可以了


是的,这确实意味着在
Base
中,对于希望与
Derived
一起使用的每个
类型
都必须添加一个
match
重载。这不起作用的原因是,派生类实际上没有覆盖基类中的虚拟函数。为了重写基类中的虚函数,派生类必须具有完全相同的签名(请参见下面的注释了解异常)。在这种情况下,签名是不同的,因为基类中的虚函数采用
void*
,而派生类中的函数采用
类型*

让我们做一个小改动,将
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");

}
#包括
阶级基础
{
公众:
Base(){}
虚拟~Base(){}
虚拟布尔匹配(const void*data)const{return false;}
};
模板
派生类:公共基
{
公众:
派生():基(){}
~Derived()重写{}
虚拟布尔匹配(常量类型*数据)常量覆盖{return true;}
};
int main(int argc,字符**argv)
{
派生*d=新派生();
基*b=d;
int i;
printf(“B match=%s\n”,B->match(&i)?“True”:“False”);
printf(“D匹配=%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; }
main.cpp:在“类派生”的实例化中:
main.cpp:24:38:从这里开始需要
main.cpp:19:16:错误:“bool-Derived::match(const-Type*)const[with-Type=int]”标记为“override”,但未重写
虚拟布尔匹配(常量类型*数据)常量覆盖{return true;}
假设我们使用的是C++11,那么最好使用
override
来确保我们确实在重写基类虚函数

上面的注释:有一种叫做a的东西,其中覆盖不必具有相同的签名,但这超出了问题的范围。

多亏了o_weisman在原始问题下的评论,我能够使用函数模板找到一个有效的解决方案(见下文)。诚然,在我的解决方案的当前形式中,我利用了一个限制,即派生的每个类型实例都是一个单例。这对我的特殊设计很有效,但行为可能是
#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