В С++, почему компилятор выбирает функцию 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(), которая позволяет вам изменять имя, а не возвращать ссылку на базовый контейнер, а затем "возможно" его изменить.