35
#include <iostream>
using namespace std;

class Base {
public:
  Base() {};
  ~Base() {};
};

template<class T>
class Derived: public Base {
  T _val;
public:
  Derived() {}
  Derived(T val): _val(val) {}
  T raw() {return _val;}
};

int main()
{
  Base * b = new Derived<int>(1);
  Derived<int> * d = b;
  cout << d->raw() << endl;
  return 0;
}

現在、ポリモーフィズムの問題がいくつかあり、上記のコードはすべてを要約しています。Base クラス ポインターを作成し、そこに新しい派生テンプレート クラスのポインターを配置しました。次に、派生テンプレート クラスの新しいポインターを作成し、基本クラスのポインターが指す参照を持たせたいと考えています。Base ポインター (b) が Derived を指していても、参照を Derived クラス ポインター (d) に渡すことはできませんthere's no known conversion from Base * to Derived<int> *

それで、それを行うためのトリックまたは代替方法はありますか? 前もって感謝します。

4

3 に答える 3

61

基本型をポリモーフィックに変更する必要があります。

class Base {
public:
    Base() {};
    virtual ~Base(){};
};

スーパータイプから派生タイプにキャストするには、次を使用する必要がありますdynamic_cast

Base *b = new Derived<int>(1);
Derived<int> *d = dynamic_cast<Derived<int> *>(b);

ここを使用dynamic_castすると、型キャストが可能であることを確認します。そのチェックを行う必要がない場合 (キャストが失敗しないため)、次を使用することもできますstatic_cast

Base *b = new Derived<int>(1);
Derived<int> *d = static_cast<Derived<int> *>(b);
于 2013-09-18T13:49:30.177 に答える
3

これを試して:

Derived<int> * d = static_cast<Derived<int>* >(b);

欠点は、Base() のインスタンスであるクラスをキャストできることです。その後、d->raw() は未定義になります (セグメンテーション違反のようです)。その場合は、dynamic_cast を使用し、少なくとも 1 つの関数を base virtual にします (多態性を扱う場合は、デストラクタを virtual にすることが不可欠です)。

仮想関数は、仮想テーブル上のポインターを使用して実装されたフードの下にあります。このポインターは、クラスの真のタイプを識別するためにも使用できます。これは、この変換を実行できるかどうかを確認するために dynamic_cast によって使用され、キャスト時にわずかな余分なオーバーヘッドが発生します。

于 2013-09-18T14:01:21.457 に答える
2

dynamic_cast を使用できます

Derived<int> * d = dynamic_cast<Derived<int> *>(b);

キャストが失敗した場合 (ベース ポインターが要求された派生型を指していない場合)、null が返されます。

ただし、dynamic_cast が機能するには、基本クラスに少なくとも 1 つの仮想関数が必要です。デストラクタを仮想にすることをお勧めします (これにより、オブジェクトを削除する他の潜在的な問題も防止されます)。

dynamic_cast を使用すると、コードの設計が不適切である可能性があります。

ベース ポインターが派生型を指していることが 100% 確実な場合は、わずかに高速な static_cast に置き換えることができます。個人的には、一般的に追加の安全チェックを好みます。

于 2013-09-18T13:51:05.980 に答える