5

よく私は次のようなコードに遭遇します

/*initializer list of some class*/:m_member(some_param,/* --> */ *this)

これが行われる理由は、m_memberがそれを含むクラスからメンバー関数を呼び出すことができるようにするためです...別名

//code in class that is m_member instance of

    m_parent->some_function();

個人的には哀れなデザイン(「親愛なる子供、クラスのカプセル化に何をしているのか知っていますか」)だと思うので嫌いですが、一般的にこの動作は悪いので、もしそうなら、この種の回避方法を知りたいです。設計。

編集:イニシャライザーリストでこれに焦点を当てないでください、それがctor本体にあるとしましょう。

4

4 に答える 4

2

あなたの親は参照セットの時間に構築されていないので、それは悲惨なことがあります。次の例はこれを示しています。

#include <iostream>
using namespace std;

struct TheParent;

struct TheChild
{
    TheChild(TheParent& parent);
    TheParent& myParent;
};

struct TheParent
{
    TheParent()
      : mychild(*this)
      , value(1)
    {
        cout << "TheParent::TheParent() : " << value << endl;
    }

    TheChild mychild;
    int value;
};

TheChild::TheChild(TheParent& parent)
   : myParent(parent)
{
    cout << "TheChild::TheChild() : " << myParent.value << endl;
};

int main()
{
    TheParent parent;
    return 0;
}

次の出力を生成し、親オブジェクトの不確定な状態を明確に示します。

TheChild::TheChild() : 1606422622
TheParent::TheParent() : 1

結論:このようにしないでください。代わりに動的な子の割り当てを使用する方が適切ですが、これにも注意が必要です。

#include <iostream>
using namespace std;

struct TheParent;

struct TheChild
{
    TheChild(TheParent& parent);
    TheParent& myParent;
};

struct TheParent
{
    TheParent()
      : mychild(NULL)
      , value(1)
    {
        mychild = new TheChild(*this);
        cout << "TheParent::TheParent() : " << value << endl;
    }

    ~TheParent()
    {
        delete mychild;
    }

    TheChild* mychild;
    int value;
};

TheChild::TheChild(TheParent& parent)
   : myParent(parent)
{
    cout << "TheChild::TheChild() : " << myParent.value << endl;
};


int main()
{
    TheParent parent;
    return 0;
}

これにより、あなたが望んでいる可能性が高いものが得られます。

TheChild::TheChild() : 1
TheParent::TheParent() : 1

ただし、がTheParent継承チェーンの中間クラスであり、まだ構築されていない派生クラスの関数のオーバーライドされる可能性のある仮想実装にアクセスしたい場合は、これでも問題が発生することに注意してください。

繰り返しになりますが、これを実行していることに気付いた場合は、そもそもなぜそうする必要があるのか​​を考えたいと思うかもしれません。

于 2012-12-19T18:07:54.927 に答える
2

m_memberが構築された時点で、親クラスがどの程度完全であるかが不明であるため、これは悪いことです。

例えば:

class Parent
{
   Parent()
   : m_member(this), m_other(foo)
   { }
};

class Member
{
    Member(Parent* parent)
    {
       std::cout << parent->m_other << std::endl; // What should this print?
    }
};

親ポインターが必要な場合のもう少し良いアプローチは、Memberがコンストラクターの本体で呼び出される'setParent'メソッドを持つことです。

于 2012-12-19T17:58:08.697 に答える
1

大多数のプログラミング慣行のように、それが一般的に悪いと言うことは不可能です(そしてあなたがそうするなら、あなたは悪い人であり、恥じるべきです)。私は時々これを使用しますが、それはまれです。ただし、クラスのデザインを変更することで意図的に避けようとすることではありません。

上記の段落で「私」をよく使用したことに注意してください。これは非常に主観的な問題であることを確認してください。

于 2012-12-19T17:55:19.983 に答える
0

私はこの言語を、与えられた問題の解決策を実装するためのツールと見なしています。設計上、C ++では明示的な使用が許可されていますがthis、他のオブジェクト指向言語では許可されていません。したがって、私は言語機能をツールボックスのツールと見なしており、ツールを引き出すための使用法が頻繁にあります。

ただし、そこでコーディングのスタイルと実践が必要になるので、自分が何をしているのかを知る必要があります。私は自分のツールの使い方を知っている必要があり、それらの使用の意味を知っている必要があります。C ++が新しいオブジェクトを初期化する順序は定義されており、これを使用している限り、問題はありません。残念ながら、人々は幸運になることがあります。また、そのようにバグを作成することもあります。あなたはあなたのツールとそれらの使い方を知る必要があります:-)

私の個人的な意見であなたの質問に答えるために:私はこの特定の構成を避けようとします、しかし時々私はそれを使わなければなりませんでした。クラスの再設計について熟考することでさえ、それを回避することはできなかったでしょう。そのため、この機会に「ああ、時々、私のデザインをクリーンクリーンストレートOOでモデル化できないことがあります。クラス間の依存関係が厳しく、パフォーマンスが非常に重要です」と提出しました。

于 2012-12-19T18:25:51.373 に答える