2011-07-06 138 views
6

我刚刚意识到要问的问题有多难......希望我能给出的例子都足够精确,足以证明我的问题,并且足够短以避免混淆一切......至少有这种可能性编辑。C++模板与继承

所以这是我目前的情况。当然,我改变了一点逻辑/结构方面(以及反正命名方面)试图把重点放在我的问题的实质:

// MyClass deals with lists (actually several data structures) of the 
// type MyType which should support different types and has to be 
// efficiently dealt with. Templating seems just right here 
class MyClass 
{ 
    ... 

    void doSomething<class MyType>(vector<MyType> someList); 

    ... 

    // At some point I have to extract elements of the type MyType. 
    // The extractor obviously depends on MyType but it is not possible to 
    // Create a general version that could use templates itself 
    // (unless I use a specialization for each possible MyType) 

    // I am stuck between these two alternatives: 

    // Possibility1: 
    // Let the client pass the right extractor and template it. 
    template<class Extractor, class MyType> 
    void extract(const Extractor& extractor, const string& source, 
       vector<MyType>* dest) 
    { 
    extractor.extract(source, dest); 
    } 

    // Possibility2: 
    // Use a member _extractor of some base type that has to be set 
    // to a specialization. The ExtractorBase has a virtual method 
    // template<T> void extract(const string& source, vector<T>* myType) = 0 
    // with no definition that is only defined in subclasses wrt certain 
    // postings. 
    ExtractorBase _extractor; 

    template<class MyType> 
    void extract(const string& source, vector<MyType>* dest) 
    { 
    _extractor.extract(source, dest); 
    } 
} 

此刻,我宁愿possibility1,因为我不我不得不在抽取器中继承MyType和相关抽取器的所有变体,我想在将来尝试。另一方面,提取器可能需要复杂的代码和若干成员(如某些输入值映射到特定值的巨大映射)。所以使用模板不会有性能提升。特别是只使用头文件提取器,甚至可能是内联的函子,都是不可能的。在过去,这对我来说是一个强烈的指向,即模板只会增加代码的复杂性(不得不处理实例化,使客户代码更难生活等),并且我应该尽量避免它。

或者还有第三种可能性我根本没有想到?

+0

“提取”是什么意思?是否只使用矢量? – vines

+0

目前还不清楚MyClass如何参与抽取过程(以及为什么extract()是MyClass的_method_) – user396672

回答

2

最好用第一个选项。它更清洁和可维护。

因为从你的意见,我想提出的是,你是一个错误的假设为第二个选项:

// The ExtractorBase has a virtual method 
// template<T> void extract(const string& source, vector<T>* myType) = 0; 

NO。这是不可能的;一个template功能永远不可能是virtual。所以要实现第二个选项,你必须选择一些肮脏而难以维护的方法,这不是一个好主意。

+0

我认为Björn意味着_extractor成员变量是一个指针,并且在调用模板函数之前实际指向适当的实现。这是可行的,但是当模板可以使用时,我并不喜欢虚拟分发:通常,编译时解决得越好越好。无论如何,这似乎是一个经典的案例:“吸引并看到”......如果它们引发一些麻烦转移到虚拟调度上,那么从模板开始......这种API实际上可以是相同的,因此所涉及的工作应该是不重要的。 –

1

我认为第一种可能性更加灵活。

在第二种可能性中,我没有看到不需要的封装提取器作为类成员的兴趣。 MyClass和Extractor之间还有更多的耦合,这不是一件好事。模板减少耦合(以某种方式),所以如果你有选择它是一个更好的。

1

你有第三种选择,提供MyType的构造函数,它知道如何从std::string构造自己。或者更好的是一对迭代器,所以如果你需要从字符串构造一个序列MyType,你可以使用范围。

+0

首先,我必须从一个字符串中提取多个MyTypes,以便只留下迭代器。虽然这是一个非常好的主意,我应该补充一点,提取器依赖于很多附加信息。最好的例子可以是将输入字符串映射到ID的“词汇表”。还是非常感谢你的帮助。 –

+0

@ b.buchhold,大概所有这些信息都是MyType的内部实现细节? – Nim

0

这听起来像Strategy Pattern的情况 - 你的类有一个操作,其实现可能会有所不同。

下面是我在不同方法中看到的折衷方案。

模板解决方案将避免必须声明抽象接口类,并使用vtbl来确定要使用哪种实现。但它会迫使你在编译时锁定到应用程序中。

继承解决方案将迫使您声明一个抽象接口类,并在vtbl.中查找执行的性能,但它可以让您在运行时选择解压缩实现。

不知道性能对您的应用程序有多重要,以及您需要如何灵活,我可能会选择继承解决方案,因为我喜欢在抽象类中定义接口的明确性并对其进行编码。