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

2 に答える 2

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

これにより、の最初のコンストラクターが呼び出されるCDerivedため、どちらがのタイプであるかT2が推測されます。次に、コンストラクターになります。つまり、は、(クラステンプレートへのtype引数の値である)を受け入れる基本クラスコンストラクターに渡されます。したがって、エラーは、に変換できません。のに注意してください。CDerived<double>dd1dd1xxCDerived<double>intTCDerivedCDerived<double>intTCBaseint

それを次のように見てください:

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

今すぐ動作するはずです:オンラインデモ

于 2012-05-25T17:21:31.403 に答える
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; 
    }
}

注: これは不適切なスタイルと見なされる場合があります。動的キャストは、オーバーロードを使用するよりも実行時にコストがかかるvirtualため、コードのリファクタリングを検討してください。

于 2012-05-25T17:33:33.047 に答える