Вызов функции const, а не ее неконстантной версии
Я пытался обернуть что-то похожее на общие указатели данных Qt для своих целей, и после тестирования я узнал, что при вызове функции const вместо него выбирается неконстантная версия.
Я компилирую с параметрами С++ 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. И когда я комментирую неконстантный, он компилируется без ошибок, поэтому это возможно. Тем не менее мой терминал печатает:
"non const data ptr"
Является ли это ошибкой GCC (у меня есть 4.5.2), или что-то мне не хватает?
Ответы
Ответ 1
Если у вас есть две перегрузки, которые отличаются только их const
-ness, тогда компилятор разрешает вызов в зависимости от того, является ли *this
const
или нет. В вашем примере кода test
не const
, поэтому вызывается перегрузка не const
.
Если вы сделали это:
testType test;
const testType &test2 = test;
test2->x();
вы должны увидеть, что вызывает другую перегрузку, потому что test2
- const
.
Ответ 2
test
является неконстантным объектом, поэтому компилятор находит наилучшее соответствие: неконстантная версия. Вы можете применять константу с static_cast
, хотя: static_cast<const testType&>(test)->x();
РЕДАКТИРОВАТЬ: В стороне, поскольку вы подозревали, что 99,9% времени вы считаете, что нашли ошибку компилятора, вы должны вернуться к своему коду, поскольку, вероятно, существует какая-то странная причуда, а компилятор фактически соответствует стандарту.
Ответ 3
Не имеет значения, является ли Data::x
постоянной функцией или нет. Вызываемый оператор принадлежит классу container<Data>
, а не классу Data
, а его экземпляр не является константой, поэтому вызывается не постоянный оператор. Если бы существовал только постоянный оператор или экземпляр класса был постоянным, то был бы вызван оператор констант.
Ответ 4
Но testType
не является объектом const.
Таким образом, он будет вызывать неконвертную версию своих членов.
Если методы имеют точно такие же параметры, он должен сделать выбор, по какой версии вызывать (поэтому он использует этот параметр (скрытый)). В этом случае это не const, поэтому вы получаете неконстантный метод.
testType const test2;
test2->x(); // This will call the const version
Это не влияет на вызов x(), так как вы можете вызвать метод const для не const-объекта.