一部のオブジェクト (大きい場合があります) へのアクセサーを持つ 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
}