在不知道C ++中的模板类型的情况下调用超级模板类方法

时间:2018-09-26 11:34:07

标签: c++ templates

我有一个使用模板的基类,它有一些不依赖于模板类型的方法,但是当我使用指针Base* a而不是派生类时,编译器会抱怨,因为没有指定的类型。我知道在Java中这是可能的,但不确定在C ++中是否可行。这是一个简单的例子:

template <typename T>
class Base {
public:
    Base(const T& t) : _t(t) {}
    virtual ~Base() { }

    void doSomething() { std::cout << "Hello world/n"; }

    virtual T getVal() const { return _t; }

private:
    T _t;
};

class DerivedA : public virtual Base<std::string>
{
public:
    DerivedA(const std::string& path) : Base<std::string>(path) {}
    virtual ~DerivedA() {}
};

class DerivedB : public virtual Base<int>
{
public:
    DerivedB(int value) : Base<int>(value) {}
    virtual ~DerivedB() {}
};

int main(int argc, const char * argv[]) {

    DerivedA d("hello world\n");
    Base* basePtr = &d; // ERROR: Use of class template 'Base' requires template arguments
    basePtr->doSomething();

预先感谢

3 个答案:

答案 0 :(得分:3)

只需创建另一个不是模板的基类:

class ReallyBase {
public:
    virtual ~ReallyBase() = default;
    void doSomething() { std::cout << "Hello world\n"; }
};

template <typename T>
class Base : public ReallyBase {
public:
    Base(const T& t) : _t(t) {}
    virtual const T& getVal() const { return _t; }    
private:
    T _t;
};

答案 1 :(得分:0)

Java中的泛型与C ++中的模板完全不同。泛型基于类型擦除,而使用模板时,每个实例化都是完全独立于不同实例化的单独类型。

在Java中,ArrayList<Integer>ArrayList<Boolean>基本相同。另一方面,对于模板,Base<int>Base<std::string>无关(除了是同一模板的两种类型),因此您的派生类实际上共享普通基类。

要解决您的问题,您可以编写一个(非模板)基类,该基类声明所有派生类的公共接口。

答案 2 :(得分:0)

让我们的 1 st 讨论您的问题的简单解决方案,编写一个推导函数:

template<typename T>
Base<T>* make_base(Base<T>* param) {
    return param;
}

您可以按以下方式使用它:

DerivedA d("hello world\n");
auto basePtr = make_base(&d);

basePtr->doSomething();

可以像this example一样进一步改进此解决方案,但是由于我认为这不是最好的解决方案,因此我不会给答案打乱,而是将这种优化留给您仔细阅读。

但是 2 nd 让我们谈谈改进设计的问题。您会注意到,任何标准容器都会创建一个using value_type = ...,从而存储它们所传递的模板类型。这对于这种确切情况很重要!如果您将using value_type = T公开添加到Base模板类中,则可以避免在一起遇到的问题,而无需使用make_base,您可以做到:< / p>

Base<decltype(d)::value_type>* basePtr = &d;

此处重要的后续概念是DerivedADerivedB并非相同的基类。因此,您永远无法做这样的事情

auto basePtr = make_base(&d);
basePtr = new DerivedB({});