0

一部のオブジェクト (大きい場合があります) へのアクセサーを持つ C++ のデータ構造クラスがあり、このアクセサーを使用する const メソッドと非 const メソッドがあるため、オーバーロードする必要があります。以下のコードの批評を探しています - 同じことをよりクリーンに達成する方法はありますか?

私が理解しているように、次のケースでアクセサーのコードを複製せずにこれを実現するには、get() メソッドの 2 つの方法があります。これら 2 つの方法のいずれかに重大な問題があるかどうかはわかりません。ここでいくつかのガイダンスをお願いします。

私が方法 A を気に入っている理由は次のとおりです。

  • 1 つの const_cast のみ
  • メソッド get() の const-version はコピーを返します
  • 非 const メソッドは、非 const 参照を直接取得します

私は方法Aが好きではありません:

  • 非 const メソッド get() は契約によってのみ const になります (コンパイラによってチェックされません)。
  • const 参照を取得するのは難しいが、不可能ではない

私が方法 B を気に入っている理由は次のとおりです。

  • const メソッド get() の const-ness は、コンパイラによってチェックされます
  • 返されたオブジェクトのコピーはユーザーによって制御されます

私は方法Bが好きではありません:

  • 読みにくい 2 つの const_casts が必要です

これは、2 つのケースの (最小限の) コード例です。

/**
 * summary:
 * Two classes with an overloaded method which is
 * guaranteed (by contract) not to change any
 * internal part of the class. However, there is a
 * version of this method that will return a non-const
 * reference to an internal object, allowing the user
 * to modify it. Don't worry about why I would ever
 * want to do this, though if you want a real-world
 * example, think about std::vector<>::front()
 *
 * The difference between A and B can be summarized
 * as follows. In both cases, the second method merely
 * calls the first, wrapped with the needed
 * const_cast's
 *
 * struct A {
 *     int& get();
 *     int  get() const;
 * };
 *
 * struct B {
 *     const int& get() const;
 *           int& get();
 * };
 *
 **/

struct A
{
    int _val;

    A() : _val(7) {};

    // non-const reference returned here
    // by a non-const method
    int& get()
    {
        // maybe lots of calculations that you do not
        // wish to be duplicated in the const version
        // of this method...
        return _val;
    }

    // const version of get() this time returning
    // a copy of the object returned
    int get() const
    {
        // CONST-CAST!!?? SURE.
        return const_cast<A*>(this)->get();
    }

    // example of const method calling the
    // overloaded get() method
    int deep_get() const
    {
        // gets a copy and makes
        // a copy when returned
        // probably optimized away by compiler
        return this->get();
    }
};

struct B
{
    int _val;

    B() : _val(7) {};

    // const reference returned here
    // by a const method
    const int& get() const
    {
        // maybe lots of calculations that you do not
        // wish to be duplicated in the non-const
        // version of this method...
        return _val;
    }

    // non-const version of get() this time returning
    // a copy of the object returned
    int& get()
    {
        // CONST-CAST!? TWO OF THEM!!?? WHY NOT...
        return const_cast<int&>(const_cast<const B*>(this)->get());
    }

    // example of const method calling the
    // overloaded get() method
    int deep_get() const
    {
        // gets reference and makes
        // a copy when returned
        return this->get();
    }
};


int main()
{
    A a;
    a.get() = 8;  // call non-const method
    a.deep_get(); // indirectly call const method

    B b;
    b.get() = 8;  // call non-const method
    b.deep_get(); // indirectly call const method
}
4

1 に答える 1

2

メンバー関数の定数は、次の質問に基づいて決定する必要があります。オブジェクトを変更するコンテキストでメンバー関数が使用されているか? (メンバーがオブジェクトを直接変更するか、外部の呼び出し元がオブジェクトを変更できるように内部データへの参照/ポインターを返す)。はいの場合は非 const にし、そうでない場合は const にします。

コンパイラは、constness のみが異なるオーバーロードを正しく選択します。ただし、戻り値の型はオーバーロードの解決では使用されません。さらに、値による/参照による返品は、予想されるコストと、返品しようとしているものの意図された所有権に基づいてのみ決定する必要があります。幸いなことに、C++11 は移動セマンティクスを提供することで作業を楽にします。これは、大規模なデータ構造を値渡しで問題なく返すことができることを意味します。参照されたオブジェクトが外部の呼び出し元より長く存続する場合にのみ、参照によって戻ります。

あなたの名前をint& get()変更する必要がvoid set(int)あり、あなたint get() constを計算ヘルパーと適切なget()

class C
{
    int val_;
public:
    void modify()   { /* some expensive computation on val_ */ }
    int get() const { return val_; }
    void set(int v) { val_ = v_; }
};

または、機能を維持したい場合はget()、次のことができます

class D
{
int val_;
public:
    void modify()    { /* some expensive computation on val_ */ }
    int get() const  { modify(); return val_; }
    int& get()       { modify(); return val_; } // no const-cast needed
};
于 2013-06-05T21:39:00.547 に答える