В С++, почему компилятор выбирает функцию non-const, когда const будет работать также?
Например, предположим, что у меня есть класс:
class Foo
{
public:
std::string& Name()
{
m_maybe_modified = true;
return m_name;
}
const std::string& Name() const
{
return m_name;
}
protected:
std::string m_name;
bool m_maybe_modified;
};
И где-то еще в коде, у меня есть что-то вроде этого:
Foo *a;
// Do stuff...
std::string name = a->Name(); // <-- chooses the non-const version
Кто-нибудь знает, почему компилятор в этом случае выбирает неконтинентную версию?
Это несколько надуманный пример, но фактическая проблема, которую мы пытаемся решить, периодически автоматически сохраняет объект, если он изменился, и указатель должен быть неконстантным, потому что он может быть изменен в какой-то момент.
Ответы
Ответ 1
Два ответа spring:
-
Неконстантная версия является более близким.
-
Если он вызвал перегрузку константы для неконстантного случая, то при каких обстоятельствах он когда-либо вызывал бы неконстантную перегрузку?
Вы можете заставить его использовать другую перегрузку, нажав a
на const Foo *
.
Изменить: От Аннотации С++
Ранее в разделе 2.5.11 понятие перегрузки функции представил. Там он отметил, что член функции могут быть перегружены просто их атрибут const. В этих случаях, компилятор будет использовать участника функция , наиболее точно соответствующая const-квалификация объекта:
Ответ 2
Потому что a не является указателем const. Следовательно, неконстантная функция является более близкой. Вот как вы можете вызвать функцию const:
const Foo* b = a;
std::string name = b->Name();
Если у вас есть как const, так и неконстантная перегрузка, и вы хотите вызвать const на неконстантном объекте, это может быть признаком плохого дизайна.
Ответ 3
Компилятор не принимает во внимание, как вы используете возвращаемое значение в его определении; что не является частью правил. Он не знает, выполняете ли вы
std::string name = b->Name();
или
b->Name() = "me";
Он должен выбрать версию, которая работает в обоих случаях.
Ответ 4
Вы можете добавить функцию "cName", которая эквивалентна "Name() const". Таким образом вы можете вызвать версию const для функции без кавычек в объект const.
Это в основном полезно при использовании нового ключевого слова auto в С++ 0x, поэтому они обновляют библиотеку, чтобы включить cbegin(), cend(), crbegin(), crend (), чтобы возвращать const_iterator, даже если объект не является константой.
То, что вы делаете, вероятно, лучше сделать с помощью функции setName(), которая позволяет вам изменять имя, а не возвращать ссылку на базовый контейнер, а затем "возможно" его изменить.