使用模板时可以使用PolyMorphism吗?

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

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

这将不起作用,因为“过滤器”中的“过滤器”仅接受1个参数。

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

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

任何想法,将不胜感激 。

最佳答案

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

例如,下面是一个函数模板,它针对类似于Random-Access Iterator概念的接口(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>::iteratorstd::deque<double>::const_iteratorlong*一起使用,它们都是不同的类型,在某些方面可能有所不同,但至少是随机访问迭代器概念的所有模型。

    (观察者会注意到,通过使用0+=,我们又在我们的契约(Contract)中要求value_type是类似算术的类型。这也是我们针对其编码的接口(interface)!)

    然后,当设计您显然打算用作FiltersFilters<FilterLike>时,您需要问问自己,FilterLike需要满足的通用最小接口(interface)是什么。如果有些FilterX几乎是FilterLike,除了某些操作外,这里有一些选项:

    正如您在问题中提到的
  • 一样,无论Filters在何处使用该特定操作,都可以对其进行特殊处理,以便对FilterX进行特殊处理-这可能是您最糟糕的事情。这种方法很脆弱,因为您必须在每个需要操作的站点上执行此操作(即使看起来现在只是一个操作,将来如何?);不方便之处在于,不能,不能在类模板函数成员的函数主体内打开类型(必须使用冗长和不明显的不同技术);并引入了耦合,即Filters必须了解FilterX -为什么要关心?
  • Filters<FilterX>写一个明确的特化名称。这与上面的操作非常相似,但是当FilterX不仅在一个或两个操作中有所不同时,这是一个有趣的选项。与以前的解决方案不同,它并不那么脆弱,因为主模板保持不变,并且所有FilterX特定的内容都放在同一位置。另一方面,如果FilterX的一半已经表现得像Filter,则这意味着必须有一半Filters<FilterLike>的代码结尾重复,或者需要一些额外的工作来重构Filters<Filter>Filters<FilterX>之间的通用代码。因此,耦合的数量各不相同-如果主模板不必了解此显式特化,那么这是一个不错的选择,您甚至不必将显式特化与主模板
  • bundle 在一起
  • 编写一个AdaptedFilterX,它是FilterLike接口(interface)的模型,并将其所有操作转发到基础FilterX。如果您有几个FilterXFilterY几乎都是Filter的模型,但是具有一个公共(public)接口(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/

    10-11 16:23