目的のためにQtの共有データポインタに似たものをラップしようとしましたが、テストの結果、const関数を呼び出す必要があるときに、代わりに非constバージョンが選択されていることがわかりました。
私はC++ 0xオプションでコンパイルしています、そしてここに最小限のコードがあります:
struct Data {
int x() const {
return 1;
}
};
template <class T>
struct container
{
container() {
ptr = new T();
}
T & operator*() {
puts("non const data ptr");
return *ptr;
}
T * operator->() {
puts("non const data ptr");
return ptr;
}
const T & operator*() const {
puts("const data ptr");
return *ptr;
}
const T * operator->() const {
puts("const data ptr");
return ptr;
}
T* ptr;
};
typedef container<Data> testType;
void testing() {
testType test;
test->x();
}
ご覧のとおり、Data.xはconst関数であるため、演算子->呼び出されるのはconst関数である必要があります。また、const以外のものをコメントアウトすると、エラーなしでコンパイルされるため、可能です。それでも私の端末は印刷します:
「nonconstdataptr」
それはGCCのバグ(私は4.5.2を持っています)ですか、それとも私が欠けているものがありますか?
const
-nessのみが異なる2つのオーバーロードがある場合、コンパイラは*this
がconst
であるかどうかに基づいて呼び出しを解決します。サンプルコードでは、test
はconst
ではないため、非const
オーバーロードが呼び出されます。
これを行った場合:
testType test;
const testType &test2 = test;
test2->x();
test2
はconst
であるため、他のオーバーロードが呼び出されることがわかります。
test
は非constオブジェクトであるため、コンパイラーは最適な一致を見つけます:非constバージョン。ただし、_static_cast
_を使用してconstnessを適用できます:static_cast<const testType&>(test)->x();
編集:余談ですが、99.9%の確率でコンパイラのバグを見つけたと思うので、おそらく奇妙な癖があり、コンパイラは実際には標準に準拠しているため、コードを再検討する必要があります。
Data::x
が定数関数であるかどうかは関係ありません。呼び出される演算子は、Data
クラスではなくcontainer<Data>
クラスに属し、そのインスタンスは定数ではないため、非定数演算子が呼び出されます。使用可能な定数演算子のみがある場合、またはクラスのインスタンス自体が定数である場合は、定数演算子が呼び出されます。
ただし、testType
はconstオブジェクトではありません。
したがって、そのメンバーの非constバージョンを呼び出します。
メソッドのパラメーターがまったく同じである場合は、呼び出すバージョンを選択する必要があります(したがって、このパラメーター(非表示のパラメーター)を使用します)。この場合、これはconstではないため、non-constメソッドを取得します。
testType const test2;
test2->x(); // This will call the const version
非constオブジェクトでconstメソッドを呼び出すことができるため、これはx()の呼び出しには影響しません。