将模板化基类的子类添加到没有超基类的容器中?

时间:2012-02-26 10:46:34

标签: c++ templates stl

我正在尝试创建一个矢量(或者任何真正的STL容器),它可以容纳一组作为一种特定类型的子类的各种对象。问题是我的基类是模板化的。

据我所知,我必须创建一个接口/抽象超级基类(不确定首选的C ++术语是什么)。我不想这样做,只是使用我的(模板化的)抽象基类。下面是一些示例代码。

基本上,有没有办法不要求WidgetInterface?那么告诉编译器忽略模板要求?如果我必须WidgetInterface,我是否正确地使用以下内容?

#include <vector>
#include "stdio.h"

enum SomeEnum{
    LOW = 0,
    HIGH = 112358
};

// Would like to remove this WidgetInterface
class WidgetInterface{
public:
    // have to define this so we can call it while iterating
    // (would remove from Widget if ended up using this SuperWidget
    // non-template baseclass method)
    virtual void method() = 0; 
};

template <class TDataType>
class AbstractWidget : public WidgetInterface{
public:
    TDataType mData;
    virtual void method() = 0;
    // ... bunch of helper methods etc
};

class EnumWidget : public AbstractWidget<SomeEnum>{
public:
    EnumWidget(){
        mData = HIGH;
    }
    void method(){
        printf("%d\n", mData); // sprintf for simplicity
    }
};

class IntWidget : public AbstractWidget<int>{
public:
    IntWidget(){
        mData = -1;
    }
    void method(){
        printf("%d\n", mData); // sprintf for simplicity
    }
};


int main(){
    // this compiles but isn't a workable solution, not generic enough
    std::vector< AbstractWidget<int>* > widgets1; 

    // only way to do store abitary subclasses?
    std::vector<WidgetInterface*> widgets2; 
    widgets2.push_back(new EnumWidget());
    widgets2.push_back(new IntWidget());

    for(std::vector<WidgetInterface*>::iterator iter = widgets2.begin();
        iter != widgets2.end(); iter++){
        (*iter)->method();
    }

    // This is what i'd _like_ to do, without needing WidgetInterface
    // std::vector< AbstractWidget* > widgets3; 

    return 0;
}

4 个答案:

答案 0 :(得分:5)

不,您不能直接使用AbstractWidget作为STL容器的参数或其他任何东西。 原因是类AbstractWidget 不存在。编译器只是一个模板来构建来自。

的类

AbstractWidget<SomeEnum>AbstractWidget<int>仅存在,因为EnumWidgetIntWidget继承了它们。

模板仅存在于编译器级别。如果代码中的任何地方都没有使用AbstractWidget<T>,那么在运行时期间会有没有跟踪

因此,您发布的代码似乎是您问题的最佳解决方案(如果不仅仅是)。

答案 1 :(得分:0)

您所做的就是解决方案:您需要一个通用类/接口,并且由于AbstractWidget是类模板,因此它不能用作所有具体类的公共类模板参数不同。所以我想,你应该选择这个班级设计。这似乎是非常合理的解决方案。

答案 2 :(得分:0)

实际上,类AbstractWidget<int>AbstractWidget<double>是不同的类,因此您的类IntWidget是第一个类的子类,但与第二个类无关。你需要有一个公共父类来放入向量,所以不幸的是你无法避免没有模板化的公共接口。

答案 3 :(得分:0)

这可能完全是错误的方向,但你可以做这样的事情:

template <class T>
class ConcreteWidget : public AbstractWidget<T>
{
};

然后使用模板专门化来定义您的特定小部件:

template <>
class ConcreteWidget : public AbstractWidget<int>
{
public:
    ConcreteWidget() : mData(-1) {}
};

template <>
class ConcreteWidget : public AbstractWidget<SomeEnum>
{
public:
    ConcreteWidget() : mData(HIGH) {}
};

所以不是拥有一个IntWidget和一个EnumWidget,而是拥有一个ConcreteWidget和ConcreteWidget,然后可以简单地拥有一个vector<WidgetInterface>,这将是所有这些通用子项的超级?

我不确定这是否能解决您的问题,甚至无法解决问题。我喜欢这个答案的反馈。