3

重複の可能性:
派生**からベース**への変換

私は、主に Python を数年間使用した後、C++ に戻ってきましたが、強く型付けされた壁にぶつかっています。私は基本的なポリモーフィズムと、基本クラスと派生クラスのポインター間の型キャストをうまく処理していると思います (たとえば、派生クラスのポインターをその基本クラスのポインターに型キャストすることはできますか? )。派生クラスへのポインターへのポインターを、その基本クラスへの p-to-p に割り当てませんか?

より多くのコンテキスト (およびおそらく、これをあまり Python らしくしないためのヒント) については、私がやろうとしていることの縮小版を次に示します。オブジェクト (単一のクラスから派生) へのポインターのリストと、それらを識別する文字列 (つまり a map<string, obj*>) が必要です。コンポーネントのセットは、識別文字列と位置のリストを渡して、対応するオブジェクト (つまり a map<string, obj**>) へのポインターを格納します。その後、文字列 ID で適切なオブジェクトを見つけ、コンポーネントが後で使用できるように適切なポインターを入力できるはずです。これを行う単純化されたコードは次のとおりです。

#include <map>
#include <string>
using namespace std;

class base
{
};

class derived: public base
{

};

typedef map<string, base**> BasePtrDict;
typedef map<string, base*> BaseDict;


int main(int argc, char* argv[])
{
    base b1, b2;
    derived d;
    derived* d_ptr;

    BaseDict base_dict;
    base_dict["b1"] = &b1;
    base_dict.insert(make_pair("b2",&b2)); // alternate syntax
    base_dict["d"]= &d;

    BasePtrDict ptr_dict;
    ptr_dict["d"] = &d_ptr;

    for (auto b = ptr_dict.begin(); b != ptr_dict.end(); b++)
        *(b->second) = base_dict[b->first];

    return 0;
}

これにより、 でコンパイル エラーが発生しptr_dict["d"] = &d_ptr;ます。なんで?C++ パラダイムでは、何をすればよいですか? reinterpret_cast<base>()どこでも醜い(安全でない?)ことを本当にする必要がありますか?

4

7 に答える 7

3

base *aを aにキャストできるようにするために必要な情報が失われていderived *ます。

が複数の基本クラスから継承する場合を考えてみましょう。そのderivedため、キャストでポインター値を調整する必要があります。次にderived *pd = static_cast<derived *>(pb)、ベースへのポインターのpb場合、ポインター調整が自動的に適用されます。

ただしderived *pd; base **ppb = &pd; *ppb = *pb、ポインター調整の適用に失敗するため、これは合法ではありません。

あなたがすべきことは次のとおりです。

base *b_ptr;
... // existing code
derived *d_ptr = static_cast<derived *>(b_ptr);
于 2012-07-11T14:28:49.410 に答える
2

derived**a を aとして扱うことが許可された場合に何が可能になるかを考えてみましょうbase**:

class base
{
};

class derived: public base
{
public:
    int boom;
}


void light_the_fuse( base** pb)
{
    *pb = new base;
}


int main()
{
    derived* pd = NULL;

    light_the_fuse( &pd);

    pd->boom = 42;  // uh oh, `pd` points to a `class base`...

    return 0;
}
于 2012-07-11T14:57:32.433 に答える
1

子からベースへの変換を行うには、タイプを関連付ける必要があります。これは、が直交ポインタ型(関連するクラスを指しているため)であるため、その子が明らかに正しくないことを意味しderived**ます。base**derived*base*

ただし、次の方法static_castではなく、これを解決できるはずです。reinterpret_cast

ptr_dict["d"] = &static_cast<base*&>(d_ptr);
于 2012-07-11T14:32:30.107 に答える
0

安全ではないため、 aDerived**にa を割り当てることはできませんし、すべきではありません。Base**キャストが許可されている場合は、Derived*型ではないDervied型を指すことができます。次の点を考慮してください。

class Base {};
class Derived: public Base {};
class Other: public Base {};

...

Derived derived;
Derived* derived_p   = &derived;   // derived_p points to derived.
Derived** derived_pp = &derived_p; // derived_p points to derived.
                                   // derived_pp points to derived_p.
Base** base_pp = derived_pp;       // derived_p points to derived.
                                   // base_pp points to derived_p.

Other other;
Other* other_p = &other;           // other_p points to other.

*bpp = op;                         // base_pp points to derived_p.
                                   // derived_p points to other.

上記のコードが有効であれば、Derived* derived = new Other().

残念ながら、何が達成されようとしているのか正確にはわからないため、代替ソリューションを提供することはできません.

于 2012-07-11T15:14:18.317 に答える
0

derived*への直接キャストbase*は問題ありませんが、それはあなたが試みていることではありません。to を実行しようとしていますderived**base**、これは暗黙のキャストではありません。それはさておき、理由を聞いてもいいですか?私は先に進んで、実際にポインターが必要かどうかを尋ねますが、ダブルポインターは必要ですか?

于 2012-07-11T14:25:29.707 に答える
0

交換がはるかに簡単になります

derived* d_ptr;

base* d_ptr;

d_ptr の正確なタイプを適用する必要がある場合はいつでもキャストを使用しますが、もちろん、オブジェクト指向の原則では、そのようなケースは非常にまれであると言われています。

于 2012-07-11T14:47:15.240 に答える
0

これは、Fred ** const を void ** const に変換するために reinterpret_cast が必要なのはなぜですか?とほとんど同じです。

2 つの異なるオブジェクト型へのポインターは、基本的に互換性がありません。ただし、例外もあります

  • Derived*to Base*... Derived と Base は関連しているため、変換が許可されます ( to に型キャストした後、ポインターは実際には型 Base*のオブジェクトを指します)Base
  • T*to void*- 許可 (上記のリンクを参照)

しかし、とは本質的に異なる型であるため、D**を に変換できる理由はありません。B**B*D*

于 2012-07-11T15:03:52.713 に答える