c++ - 将多态性与模板结合使用

标签 c++ templates oop

使用模板时是否可以使用多态性?

例如,我有一个名为“Filters”的类,并且我有许多不同的变体/类来过滤数据,因此我根据模板初始化一个对象(哪种类型的过滤器在 main 中定义)

#include "Filter1.h"
#include "Filter2.h"
template<typename T>
class Filters {

public:

    void Filter(vector<double> &vec) {

        T type;

        type.Filter(vec);
    }
};


// class Filter1
class Filter1 {
   public:

      void Filter(vector<double> &vec) {

         // Code for "Filter1"

      }
};

// MAIN

int main() {
   vector<double> sample; // this is a sample vector
   Filters<Filter1> exam1;
   exam1.filter(sample);
}

但是,在“Filter2”中,假设我们传递了更多参数:

 class Filter2 {

  public:
     void Filter(vector<double> &vec, double point)
     {
         // Filter 2
     }        
 };

然后是主要内容:

int main()
{
    vector<double> sample;
    double point = 9;

    Filters<Filter2> exam;
    exam.Filter(sample, point);
}

这不起作用,因为“Filters”中的“Filter”只接受 1 个参数。

我遇到的问题是过滤器接受的参数不同。例如,“Filter1”传递一个 2D vector 和一个 double,但此类中的 Filter 方法定义仅接受 1D vector 。

我在想(理论上)我可以有一个 switch 语句(“T”)来提供不同类的初始化。

任何想法将不胜感激。

最佳答案

当您使用模板进行通用编程时,您需要针对接口(interface)进行编码。我在这里没有使用该术语的 OOP 含义——而是更广泛的含义。

作为示例,下面是一个针对随机访问迭代器概念类接口(interface)进行编码的函数模板:

template<typename It>
typename std::iterator_traits<It>::value_type
sum(It first, It last)
{
    typedef typename std::iterator_traits<It>::difference_type diff_t;
    diff_t const size = last - first;

    typename std::iterator_traits<It>::value_type accum = 0;
    for(diff_t i = 0; i != size; ++i) {
        accum += first[i];
    }

    return accum;
}

(这个例子当然是假的,这里的目的是展示多个随机访问迭代器操作。)

因为我们在契约(Contract)中指定 It是一个随机访问迭代器,我们知道sum可以访问:

  • 成员类型 std::iterator_traits<It>::value_typestd::iterator_traits<It>::difference_type ,这些类型可以从 operator[] 的结果初始化和operator-分别
  • It 上的操作喜欢 operator-operator[] ,这些可用于例如双向迭代器

因此sum可与 std::vector<int>::iterator 一起使用, std::deque<double>::const_iteratorlong* ,它们都是不同的类型,在某些方面可能有所不同,但至少都是随机访问迭代器概念的模型。

(细心的人会注意到,通过使用0+=,我们反过来要求我们的合约中value_type是一个类似算术的类型。这又是我们编码所针对的接口(interface)!)

然后在设计你的Filters时您显然打算将其用作 Filters<FilterLike> ,你需要问自己 FilterLike 的常见最小接口(interface)是什么?需要满足。如果有的话FilterX其中几乎FilterLike除了某些操作之外,这里有一些选项:

  • 正如您在问题中提到的,无论 Filters使用该特定操作,您可以将其特殊化,以便 FilterX是经过特殊处理的——这可能是你能做的最糟糕的事情。它很脆弱,因为你必须在每个需要操作的站点都执行此操作(即使现在看起来只有一个,将来呢?);不方便,因为不,您不能在类模板函数成员的函数体内打开类型(您必须使用冗长且不明显的不同技术);它引入了耦合 Filters必须了解FilterX -- 为什么要关心?

  • Filters<FilterX> 编写显式特化。这与上面的很相似,但是当 FilterX 时这是一个有趣的选择。差异不仅仅在于一两个操作。与之前的解决方案不同,这并不那么脆弱,因为主模板保持不变,并且所有 FilterX特定的东西放在同一个地方。另一方面,如果 FilterX 的一半已经表现得像 Filter ,那么这必定意味着有一半的代码 Filters<FilterLike>结束重复或需要一些额外的工作来重构 Filters<Filter> 之间的公共(public)代码和Filters<FilterX> 。因此,耦合量会有所不同 - 如果主模板不必了解此显式特化,那么这是一个不错的选择,您甚至不必将显式特化与主模板捆绑在一起

    <
  • 写一个AdaptedFilterX这是 FilterLike 的模型接口(interface)并将其所有操作转发到底层 FilterX 。如果您有多个FilterX , FilterY这几乎都是 Filter 的型号但有一个通用的接口(interface),你可以写一个AdaptedFilter<FilterX> -- 从某种意义上说 AdaptedFilter模板“转换” FilterXLike 的模型进入 FilterLike 的模型

顺便说一句,如果您使用 C++11,您可以编写 Filter接受任意参数来构造 FilterLike与:

template<typename... Args>
void Filter(Args&&... args)
{
    FilterLike filter(std::forward<Args>(args)...);
    // go on using filter...
}

仅接受 FilterLike 可能更简单(并且适用于 C++03)。不过:

void Filter(FilterLike filter)
{
   // go on using filter...
}

关于c++ - 将多态性与模板结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13662094/

相关文章:

oop - Scala 的模式匹配是否违反了开放/封闭原则?

javascript - 在 html 中创建对象并在 oop 中使用函数被认为是不好的做法吗?

c++ - 在类内声明模板化函数(通过容器类型)并在模板类之外通过容器类型定义它 -

c++ - C 中的模板化仿函数。类模板与函数模板

php - 将多维数组对象映射到类中的变量

c++ - 直接访问结构的元素

c++ - 内联函数作为模板参数,不使用函数指针

C++ STL : a good way to parse a sensor response

c++ - Hexfloat 机械手和精度

c++ - 函数返回另一个函数