5

C++ ではポインターを使用しないように言われました。しかし、私が書こうとしているコードでは、それらを避けることはできないようです。あるいは、他の優れた C++ 機能を見逃している可能性があります。

別のクラス (class2) をデータ メンバーとして含むクラス (class1) を作成したいと考えています。次に、class2 に class1 を認識させ、それと通信できるようにします。

class2 のメンバーとして class1 への参照を持つことができますが、それは、class2 のコンストラクターでパラメーターとして class1 への参照を提供し、不要な初期化リストを使用する必要があることを意味します。コンストラクターを使用せずにこれを実行しようとしています。

class2 には、class1 への参照を取り込める Initialise というメンバー関数が必要ですが、これはポインターを使用しないと不可能のようです。人々はここで何をお勧めしますか? 前もって感謝します。

コードは、主なアイデアを理解するために完全に単純化されています。

class class1
{
    public:
        InitialiseClass2()
        {
            c2.Initialise(this);
        }

    private:
        class2 c2;

};

class class2
{
    public:
        Initialise(class1* c1)
        {
            this->c1 = c1;
        }

    private:
        class1* c1;

};
4

5 に答える 5

6

これは、ポインターを使用しないと不可能のようです

それは正しくありません。実際、他のオブジェクトへの参照を処理するには、参照をコンストラクターに取ります。

class class2
{
    public:
        class2(class1& c1)
           : c1(c1)
        {}

    private:
        class1& c1;
};

ここで重要なのは、参照を割り当てるのではなく、初期化することです。これが可能かどうかは、関数を削除して RAII に落ち着くことができるかどうかにかかっていますInitialise(そうしてください!)。その後、これが実際に良いアイデアであるかどうかは、ユース ケースによって異なります。今日では、代わりにスマート ポインター型のいずれかを使用することで、所有権と有効期間のセマンティクスをより明確にすることがほぼ確実にできますstd::weak_ptr

とにかく、もっと一般的に言えば。

ポインターは「常に」悪いですか? いいえ、もちろん違います。動的メモリを自分で管理することは「常に」悪いことだと言いたくなるかもしれませんが、一般化はしません。

それらを避けるべきですか?はい。

違いは、後者は手動のメモリ管理からあなたを遠ざけるためのガイドラインであり、前者は禁止の試みであるということです。

于 2015-10-15T13:43:52.073 に答える
4

いいえ、C++ でポインターを使用することはまったく悪いことではありません。この反論を何度も目にします。悪いのは、ポインターを管理する低レベルのエンティティを作成していない限り、自分でポインターを管理することです。

繰り返しますが、私は非常に明確な区別をします。ポインタを使用するのは良いことです。USING ポインターなしで実行できる実際の C++ プログラムはほとんどありません。ポインター マネージャーで作業している場合を除き、ポインターの管理は良くありません。

于 2015-10-15T13:37:42.697 に答える
3

ポインターは可能ですnullptrが、参照は常に何かにバインドする必要があります (その後、別のものに再バインドすることはできません)。

これが主な違いであり、デザインを選択する際の主な考慮事項です。

std::shared_ptrポインタのメモリ管理は、必要に応じて委任できますstd::unique_ptr

于 2015-10-15T13:40:40.293 に答える
0

まあ、私は相互参照を持つために2つのクラスを必要としたことは一度もありませんでしたが、正当な理由から、これらのクラスをテストする方法をどのように知っていますか? 後で 2 つのクラスの通信方法を変更する必要がある場合は、おそらく両方のクラスのコードを変更する必要があります)。さまざまな方法で回避できます

  1. 実際には1つのクラスだけが必要な場合があります(多くのクラスに分割されています)
  2. クラスの Observer を登録できます (3 番目のクラスを使用すると、最終的にポインターになりますが、少なくとも 2 つのクラスの結合が少なくなり、テストが容易になります)。
  3. 他のクラスのメソッドを呼び出すために1つのクラスのみを必要とする新しいインターフェースを(おそらく)考えることができます
  4. クラスのメソッドの 1 つにラムダ (または C++11 を持っていない場合はファンクター) を渡すことができ、後方参照の必要がなくなります。
  5. メソッド内でクラスの参照を渡すことができます。
  6. おそらく、いくつかのクラスが必要であり、実際には、両方のクラスと通信するための 3 番目のクラスが必要です。
  7. 訪問者が必要な可能性があります (実際には複数のディスパッチが必要な場合もあります)。

上記の回避策には、ポインタが必要なものとそうでないものがあります。あなたに選択;)

注:しかし、あなたがしていることは私にとってはまったく問題ありません(コンストラクターでのみトリックを行っているようですが、おそらくコードを省略しているため、問題が発生する可能性があります)。私の場合、あるクラスを別のクラスに「登録」し、コンストラクターが呼び出された後、他のクラスを呼び出すクラスは1つだけで、その逆はありません。

于 2015-10-15T13:58:17.890 に答える
0

まず第一に、設計に循環依存がある場合は、それについてよく考えて、それが正しい方法であることを確認してください。依存関係を分析して修正するために、依存関係逆転の原則を使用してみてください。

C++ ではポインターを使用しないように言われました。しかし、私が書こうとしているコードでは、それらを避けることはできないようです。あるいは、他の優れた C++ 機能を見逃している可能性があります。

ポインタは強力なプログラミング ツールです。C++ (または一般的なプログラミング言語) の他の機能と同様に、適切なツールである場合に使用する必要があります。C++ ではさらに、使用法はポインターに似ていますが、より優れた構文を持つ参照にアクセスできます。さらに、null にすることはできません。したがって、それらは常に有効なオブジェクトを参照します。

そのため、必要な場合はポインターを使用しますが、生のポインターの使用を避け、可能な限り代わりにスマート ポインターを使用するようにしてください。これにより、いくつかの些細なメモリリークの問題から保護されますが、オブジェクトのライフサイクルに注意を払う必要があり、動的に割り当てられたオブジェクトごとに、誰がそれを作成し、いつ/誰がオブジェクトに割り当てられたメモリを解放するかを明確に把握する必要があります.

ポインター (および参照) は、参照によってメソッドにパラメーターを渡すために使用できるため、スタック内の値によって重いオブジェクトを渡すことを回避できるため、一般的に非常に便利です。たとえば、重いオブジェクト (copy/= 演算子は時間がかかる) の非常に大きな配列があり、これらのオブジェクトを並べ替えたい場合を想像してください。簡単な方法の 1 つは、これらのオブジェクトへのポインターを使用することです。そのため、並べ替え操作中にオブジェクト全体を移動する代わりに、非常に軽量なデータ型 (基本的にマシン アドレスのサイズ) のポインターを移動するだけです。

于 2015-10-15T14:14:53.690 に答える