模板类继承

4

我有一个问题,涉及以下代码片段(这是一个非常简化的示例,可以重现我的程序中的错误):

#include <iostream>

using namespace std;

template<class T> class CBase
{
    public:
        template <class T2> CBase(const T2 &x) : _var(x) {;}
        template <class T2> CBase (const CBase<T2> &x) {_var = x.var();}
        ~CBase() {;}
        T var() const {return _var;}
    protected:
        T _var;
};

template<class T> class CDerived : public CBase<T>
{
    public:
        template <class T2> CDerived(const T2 &x) : CBase<T>(x) {;}
        template <class T2> CDerived (const CBase<T2> &x) : CBase<T>(x) {;}
        ~CDerived() {;}
};

int main()
{
    CBase<double> bd(3);
    CBase<int> bi(bd); // <- No problem
    CDerived<double> dd1(3);
    CDerived<double> dd2(dd1);
    CDerived<int> di(dd1); // <- The problem is here
    return 0;
}

错误如下:

error: cannot convert 'const CDerived<double>' to 'int' in initialization

如何解决这个问题?(优先在基类中进行修改,而不是在派生类中进行修改,如果可能的话,不使用虚拟性)。非常感谢。
编辑: 如果我将有关行替换为:CDerived<int> di(CBase<int>(CBase<double>(dd1)));它就可以工作了,但不太实用...
编辑:似乎通过以下方法解决了:
template <class T2> CDerived(const CDerived<T2> &x) : CBase<T>(static_cast<const CBase<T2>&>(x)) {;}
2个回答

5
CDerived<int> di(dd1); // <- The problem is here

这会调用CDerived的第一个构造函数,因此T2被推断为CDerived<double>,这是dd1的类型。然后,dd1在构造函数中变成了xxCDerived<double>,被传递给接受int(即T作为CDerived类模板的类型参数的值)的基类构造函数。因此出现错误,因为CDerived<double>无法转换为int。请注意,CBaseTint
将其视为:
CDerived<int> di(dd1); // <- The problem is here
          ^       ^
          |       |
          |       this helps compiler to deduce T2 as double
          |
          this is T of the CDerived as well as of CBase

如果你想让你的代码工作,那么请执行以下步骤:
  1. 首先公开派生而不是私有派生。
  2. 添加另一个构造函数,将 CDerived<T2> 作为参数。
所以你需要这样做:
template<class T> class CDerived : public CBase<T>  //derived publicly
{
    public:
        template <class T2> CDerived(const T2 &x) : CBase<T>(x) {;}

        //add this constructor
        template <class T2> CDerived(const CDerived<T2> &x) : CBase<T>(x.var()) {;}

        template <class T2> CDerived (const CBase<T2> &x) : CBase<T>(x) {;}
        ~CDerived() {;}
};

现在应该可以工作了:在线演示

是的,我理解了。我的问题是:如何修改基类,使其能够从CDerived<double>构造出CDerived<int>? - Vincent
@Vincent:你从CBase中私有地派生出来了。这是故意的还是一个错误? - Nawaz
非常有趣。但它调用了第一个构造函数(这在示例中可以工作,但在我的程序中我需要调用第二个构造函数)。受你的代码启发,我尝试了这个:template <class T2> CDerived(const CDerived<T2> &x) : CBase<T>(static_cast<const CBase<T2>&>(x)) {;}。它可以编译,但您认为这是正确的方式吗? - Vincent
@Vincent:那也应该可以。事实上,这是一个很好的做法。 - Nawaz

0
尝试在您的基类中创建另一个构造函数,该构造函数接受一个通用对象并使用动态转换分配值。
template <class T2> CBase (const Object &x) : _var() {
    try {
        const CBase<T2> &x_casted = dynamic_cast<const CBase<T2> &> (x);
        _var = x_casted.var();
    }
    catch {
        std::cerr << "Object not of type CBase" << std::endl; 
    }
}

注意:这可能被认为是不良风格。动态转换在运行时比使用虚函数和重载更昂贵,因此请考虑重构您的代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接