20

たとえば、次のクラスがあるとします。

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

この場合、コンパイラが非 const バージョンを選択する理由を知っている人はいますか?

これはやや不自然な例ですが、解決しようとしている実際の問題は、オブジェクトが変更された場合にオブジェクトを定期的に自動保存することであり、ポインターはある時点で変更される可能性があるため、非 const でなければなりません。

4

4 に答える 4

18

次の 2 つの答えが思い浮かびます。

  1. const 以外のバージョンは、より厳密に一致します。

  2. 非 const ケースに対して const オーバーロードを呼び出した場合、どのような状況で非 const オーバーロードを呼び出すでしょう?

にキャストすることで、他のオーバーロードを使用できるようになりaますconst Foo *

編集: C++ 注釈から

以前のセクション 2.5.11 で、関数のオーバーロードの概念が導入されました。そこでは、メンバー関数は const 属性だけでオーバーロードされる可能性があることに注意してください。そのような場合、コンパイラは、オブジェクトの const 修飾に最も近いメンバー関数を使用します。

于 2008-10-02T19:30:20.333 に答える
18

a は const ポインターではないためです。したがって、const 以外の関数がより一致します。const 関数を呼び出す方法は次のとおりです。

const Foo* b = a;
std::string name = b->Name();

const と非 const の両方のオーバーロードがあり、非 const オブジェクトで const を呼び出したい場合、これは設計が悪いことを示している可能性があります。

于 2008-10-02T19:31:59.363 に答える
7

コンパイラは、その決定において戻り値をどのように使用しているかを考慮しません。それはルールの一部ではありません。あなたがやっているかどうかはわかりません

std::string name = b->Name();

また

b->Name() = "me";

どちらの場合でも機能するバージョンを選択する必要があります。

于 2008-10-02T19:46:58.890 に答える
2

「Name() const」と同等の「cName」関数を追加できます。このようにして、最初に const オブジェクトにキャストせずに関数の const バージョンを呼び出すことができます。

これは、C++0x の新しいキーワード auto で最も役立ちます。そのため、ライブラリを更新して cbegin()、cend()、crbegin()、crend() を含め、オブジェクトが非オブジェクトであっても const_iterator を返すようにしています。定数。

あなたがやっていることは、基になるコンテナーへの参照を返すのではなく、名前を変更できる setName() 関数を使用することでおそらくより適切に実行され、「おそらく」変更されます。

于 2008-10-02T20:49:10.893 に答える