web-dev-qa-db-ja.com

c ++-基本クラスポインターを派生クラスポインターに変換する

#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ポインター(b)はDerivedを指しますが、参照はDerivedクラスポインター(d)に渡すことができません。なぜならthere's no known conversion from Base * to Derived<int> *(コンパイラーの言うとおり)。

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

22
Andy Autida

基本型を多態的に変更する必要があります。

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);
41
Abrixas2

これを試して:

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

欠点は、Base()のインスタンスであるクラスをキャストでき、d-> raw()が未定義になることです(セグメンテーションフォールトリクリー)。それが当てはまる場合は、dynamic_castを使用し、少なくとも1つの関数ob base virtualを使用します(polmorphismを使用する場合は、デストラクターvirtualが不可欠です)。

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

2
Luka Rahne

Dynamic_castを使用できます

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

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

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

Dynamic_castを使用すると、コードのデザインが不適切である可能性があります。

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

2
Neil Kirk