使用模板函数设计层次类

2022-01-24 00:00:00 templates polymorphism c++

我正在编写一个类 Base,它的成员函数采用模板参数:

I am writing a class Base which has a member function taking a template parameter:

class Base {
  template<class T>
  void func(const T& t) { ... }
};

有一个类Derived,它在概念上继承了Base的性质,具有相同的func函数,但实现不同.

There's a class Derived which conceptually inherits natures of Base and has the same function func with different implementation.

一开始我想从Base派生Derived,把func变成虚拟的,但是我做不到,因为它是模板.

At first I thought of deriving Derived from Base and make func virtual, but I can't because it's template.

我也想过 CRTP,但它是一个选项,因为实例必须能够放入容器中并且可以在不知道它们的确切类型的情况下访问:

I also thought of CRTP, but it's an option because instances must be able to put into a container and be accessible without knowing exact types of them:

std::vector<Base*> v = ...;
v[0]->func(...);
v[1]->func(...);

重载可能的 T 类型也不是一种选择.

Overloading for possible types of T is also not an option.

这种情况的最佳解决方案是什么?

What is the best solution to this situation?

除了主题之外,您会推荐此类问题的参考资料(最好是书籍)吗?

And aside from the topic, would you recommend references (preferably books) for such kind of problems?

推荐答案

这不是 C++ 容易做到的.它与称为第一类多态性"的东西有关,这意味着如果 C++ 中的值可以具有多态类型,那将很容易.事实并非如此.

This is not something easily done with C++. It's related to something called "first class polymorphism", which means it would be easy if the values in C++ could have polymorphic types. This is not the case.

如果您可以使用通用解决方案(这意味着代码 f 对于所有 T 必须相同),您也许可以这样做,但它将是一项艰巨的任务.

If you'll be fine with a generic solution (that means the code f must be the same for all T), you can maybe do it, but it will be a laborious task.

基本上,您需要将 const T &t 参数替换为类型不是通用的参数,但会捕获内部"所有行为 f 需要来自所有可能类型的 t.

Basically, you'll want to replace your const T &t parameter with a parameter whose type that wouldn't be generic, but will capture "inside" all the behaviour f needs from ts of all possible types.

例如,假设 T 是一个函子,f 使用 int 参数调用.在这种情况下,您需要将声明更改为

For an example, let's say T is meant to be a functor, that f calls with an int argument. In this case, you'll change the declaration to

  virtual void func(const std::function<void(int)>& t) { ... }

虚拟功能将开始工作.但是,这意味着 Ts 的接口必须在您开始在派生类中实现它之前修复(这意味着如果您改变主意并想要调用 tostream 类型的参数,你运气不好).

and virtual functions will start to work. However, that means the interface of Ts will have to be fixed before you start to implement it in derived classes (meaning if you change your mind and want to call t with an argument of type ostream, you're out of luck).

但是,创建这样的多态包装器很容易(就像 boost::any, boost::function)很难甚至不可能(any_iterator).这很大程度上取决于你想做什么.

However, creating such polymorphic wrappers ranges from easy (as is boost::any, boost::function) to hard or even impossible (any_iterator). It's very dependent on what you want to do.

相关文章