使用模板时可以使用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_type
和std::iterator_traits<It>::difference_type
,它们是可以分别从operator[]
和operator-
的结果初始化的类型It
的operator-
和operator[]
)不适用于例如双向迭代器这样
sum
可以与std::vector<int>::iterator
,std::deque<double>::const_iterator
和long*
一起使用,它们都是不同的类型,在某些方面可能有所不同,但至少是随机访问迭代器概念的所有模型。(观察者会注意到,通过使用
0
和+=
,我们又在我们的契约(Contract)中要求value_type
是类似算术的类型。这也是我们针对其编码的接口(interface)!)然后,当设计您显然打算用作
Filters
的Filters<FilterLike>
时,您需要问问自己,FilterLike
需要满足的通用最小接口(interface)是什么。如果有些FilterX
几乎是FilterLike
,除了某些操作外,这里有一些选项:正如您在问题中提到的
Filters
在何处使用该特定操作,都可以对其进行特殊处理,以便对FilterX
进行特殊处理-这可能是您最糟糕的事情。这种方法很脆弱,因为您必须在每个需要操作的站点上执行此操作(即使看起来现在只是一个操作,将来如何?);不方便之处在于,不能,不能在类模板函数成员的函数主体内打开类型(必须使用冗长和不明显的不同技术);并引入了耦合,即Filters
必须了解FilterX
-为什么要关心? Filters<FilterX>
写一个明确的特化名称。这与上面的操作非常相似,但是当FilterX
不仅在一个或两个操作中有所不同时,这是一个有趣的选项。与以前的解决方案不同,它并不那么脆弱,因为主模板保持不变,并且所有FilterX
特定的内容都放在同一位置。另一方面,如果FilterX
的一半已经表现得像Filter
,则这意味着必须有一半Filters<FilterLike>
的代码结尾重复,或者需要一些额外的工作来重构Filters<Filter>
和Filters<FilterX>
之间的通用代码。因此,耦合的数量各不相同-如果主模板不必了解此显式特化,那么这是一个不错的选择,您甚至不必将显式特化与主模板AdaptedFilterX
,它是FilterLike
接口(interface)的模型,并将其所有操作转发到基础FilterX
。如果您有几个FilterX
,FilterY
几乎都是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/