13

これは、おそらくコード例で最もよく示されています。以下は g++ でのコンパイルに失敗します。

struct Base {
};

struct Derived : public Base {
};

struct Container {
    Derived data_;
};

int main(void) {
    Base Container::*ptr = &Container::data_;
}

次のエラーが表示されますinvalid conversion from 'Derived Container::*' to Base Container::*'。これは言語で許可されていませんか?これはコンパイラのバグですか? 間違った構文を使用していますか?

助けてください!

なぜこれをやろうとしているのかについての背景: 主に派生型として使用したいメンバー データがいくつかありますが、いくつかの共通コードを介してデータを入力できるようにしたいと考えています。データは任意の順序で送信され、入力する適切なメンバー データを選択するために使用する文字列ラベルがあります。std::map<std::string, Base Container::*>共通のインターフェイスを介して各メンバーにデータを割り当てるを作成することを計画していました。if else適切なメンバーデータを見つけるために巨大な構造を持たないようにしたいと思います。

4

9 に答える 9

3

これはコンパイラのバグではありません。それはできません。(ただし、Base::* を Derived::* に割り当てることはできます)。

制限の正当な理由はわかりません (メンバー ポインターの表現がさらに複雑になる多重継承のケースを処理することを除いて)。

于 2011-05-16T13:27:58.800 に答える
1

このスレッドには、かなり複雑で、よく説明されていないものや、単純な間違った答えがいくつかあります。

しかし、私には、問題は単純に内部にメンバーがいないこと、つまりBaseメンバーContainerが存在することだと思われますDerived。あなたはこれを行うことはできません:

Base Container::*ptr = &Container::data_;

...同じ理由で、これを行うことはできません:

int a;
long* pl = &a;

2 番目の例では、オブジェクトは ではなく、longですint。同様に、最初の例では、オブジェクトは ではなく、BaseですDerived

おそらく分岐点として、あなたが本当にやりたいことはBase、抽象クラスであり、メンバーではなくを持っContainerているように思えます。Base*Derived

于 2011-05-16T13:55:01.410 に答える
1

C++ のメンバーへのポインターは、実際にはポインターではなく、特定のメンバーへのオフセットに似ており、型に固有であるため、実行しようとしている操作は実際にはサポートされていません。

ここでは、Stackoverflow C++ に関するまともな議論を次に示します。 クラス データ メンバーへのポインター

于 2011-05-16T13:26:02.950 に答える
0

A と B の間で変換が可能であっても、C::*A を C::*B に変換することはできません。

ただし、これを行うことができます:

struct Base
{
    virtual ~Base() {}
    virtual void foo() { std::cout << "Base::foo()\n"; }
};

struct Derived : Base
{
    void foo() { std::cout << "Derived::foo()\n"; }
};

struct Bar
{
    Base* x;

    Bar() : x(new Derived) {}
};

int main()
{
    Bar b;
    Base* Bar::*p = &Bar::x;
    (b.*p)->foo();
}
于 2011-05-16T13:39:01.930 に答える
0

static_cast5.3.9/9 に見られるように、この変換を行う必要があります。この理由は、static_cast親オブジェクトから子オブジェクトへのポインターとして機能するためです。つまり、派生メンバーへのポインターを親メンバーへのポインターに配置すると、親オブジェクトまたはポインターから存在しない派生メンバーにアクセスできる可能性があります。標準でこれが自動的に許可されている場合、適切な子の型ではない (そのメンバーを含む) クラスの子メンバーにアクセスしようとするのは簡単です。

Baseこれ以上の情報がなければ、ここでメンバーへのポインターを使用しようとするのではなく、クラスに別の/より良いコンストラクター/セットインターフェイスが必要なようです。

于 2011-05-16T13:39:38.467 に答える
0

あなたはただ書く必要があります:

Base* ptr = &container.data_;

containerのインスタンスである必要がContainerあるため、そのタイプの変数をどこかに作成する必要があります。

于 2011-05-16T13:21:46.817 に答える
0

あなたが望むのは「コンテナ」、つまりポインタだけを持つ構造体だと思います:

struct Container{
    Base* derivedAdata_;
    Base* derivedBdata_;
    ...
};

これで、特定のタイプ (DerivedA、DerivedB など) であることがわかっている各メンバーが後でダウンキャストできるようになりました。

ただし、最初にデータを (任意の順序で) 受け取りますが、名前は文字列であるため、マップが必要です。

std::map<std::string, Base* Container::*>

そして、あなたはすでにマップにデータを入力している必要があります:

myMap["DerivedA"] = &Container::derivedAdata;
...

これでデータが到着し、コンテナーへの入力を開始します。

instance.*(myMap[key]) = factory(key, data);

myMap[key]コンテナーの適切なメンバーを選択し、factory(key,data)インスタンスを作成します。

とにかく、マップをコンテナとして持つことができます:std::map<std::string, Base*>

于 2011-05-16T13:43:00.043 に答える
-1
struct Container {
   Derived data_; 
};  

int main(void) 
{
   Base Container::*ptr = &Container::data_;
} 

最初の問題は、Containerというメンバーがいないことですptr

Container container_object;
Base *ptr = container_object.data_;

うまくいくでしょう。data_ メンバーを作成するにはコンテナ オブジェクトが必要であり、公開する必要があることに注意してください。

代わりの方法は、derived::data_ を静的メンバーにすることです。

于 2011-05-16T14:22:59.317 に答える