我有一个使用模板的基类,它有一些不依赖于模板类型的方法,但是当我使用指针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();
预先感谢
答案 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;
此处重要的后续概念是DerivedA
和DerivedB
并非相同的基类。因此,您永远无法做这样的事情
auto basePtr = make_base(&d);
basePtr = new DerivedB({});