C++ 模板类继承

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10758686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:25:18  来源:igfitidea点击:

Template class inheritance

c++templatesinheritance

提问by Vincent

I have a problem with the following piece of code (it is a very simplified example that reproduce the error in my program) :

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

#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;
}

And the error is the following :

错误如下:

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

How to solve that ? (with a preference for modifications in the base class and not in the derived class, and if possible no use of virtuality)

如何解决?(优先在基类而不是派生类中进行修改,如果可能,不使用虚拟性)

Thank you very much

非常感谢

EDIT : If I replace the concerned line with : CDerived<int> di(CBase<int>(CBase<double>(dd1)));it works but it is not very practical...

编辑:如果我将相关行替换为:CDerived<int> di(CBase<int>(CBase<double>(dd1)));它可以工作,但不是很实用......

EDIT : Seems to be solved by that :

编辑:似乎可以通过以下方式解决:

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

回答by Nawaz

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

This invokes the first constructor of CDerived, and so T2is inferred as CDerived<double>which is the type of dd1. Then, dd1becomes xin the constructor; xwhich is CDerived<double>, gets passed to the base class constructor which accepts int(which is the value of the type argument Tto CDerivedclass template). Hence the error, as CDerived<double>cannot be converted into int. Note that Tof CBaseis int.

这会调用 的第一个构造函数CDerived,因此T2推断为CDerived<double>的类型dd1。然后,在构造函数中dd1变成xx其是CDerived<double>,被传递给基类构造函数,它接受int(这是类型参数的值T,以CDerived类模板)。因此错误, asCDerived<double>不能转换为int. 注意TCBaseint

See it as:

将其视为:

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

If you want to make your code work, then do this:

如果您想让代码正常工作,请执行以下操作:

  1. First derive publiclyinstead of privately.
  2. Add another constructor taking CDerived<T2>as parameter.
  1. 首先公开而不是私下派生。
  2. 添加另一个CDerived<T2>作为参数的构造函数。

So you need to so this:

所以你需要这样做:

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() {;}
};

It should work now : online demo

现在应该可以使用了:在线演示

回答by Hans Z

Try making another constructor that takes a generic object in your base class and assigns the value using dynamic casting.

尝试创建另一个构造函数,它在您的基类中接受一个通用对象并使用动态转换分配值。

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; 
    }
}

Note: This might be considered poor style. Dynamic casting is more expensive during runtime than using virtualand overloads, so consider refactoring your code.

注意:这可能被认为是糟糕的风格。动态转换在运行时比 usingvirtual和重载更昂贵,因此请考虑重构您的代码。