4

例として、次の(簡単な)インターフェイスを使用します。

struct IObject
{
  virtual ~IObject() {}

  virtual std::string GetName() const = 0;
  virtual void ChangeState() = 0;
};

ロジックは、それがメンバー関数であるGetNameべきであるが、そうではないことを指示します。constChangeState

ただし、これまでに見たすべてのコードは、このロジックに従っていません。つまり、上記の例では、メンバー関数GetNameとしてマークされていません。const

これは怠惰/不注意ですか、それともこれには正当な理由がありますか?constクライアントが論理的に要求されたときにメンバー関数を実装するように強制することの主な短所は何ですか?


編集:皆さんの回答に感謝します。私はそれがほぼ満場一致だと思います:怠惰/無知が私が見ているものの理由です。

4

3 に答える 3

10

怠惰/不注意だと思います。GetName()オブジェクトの状態に影響を与えないようにする必要があり、のコントラクトはIObjectその事実を明示的に示す必要があります。

継承クラスが何らかの理由でGetName()(隠された!)副作用を持たせるように強制された場合、それらは常に対応するフィールドを。として宣言できますmutable

于 2010-05-19T16:36:43.213 に答える
6

これは怠惰/不注意ですか、それともこれには正当な理由がありますか?

前者。これを正しく行うコードを実際に見たことがない場合は、すぐに新しいジョブを取得してください

constクライアントが論理的に要求されたときにメンバー関数を実装するように強制することの主な短所は何ですか?

これにより、コンパイラはコンパイル時に一般的なバグを発見できます。(コンパイル時に発見されたエラーに勝るものはありません。デスクで失敗したものはすべて、クライアントのサイトで失敗することはありません。)


10年以上前、私が新しい会社に加わり、彼らのプロジェクトの1つをハッキングした直後に、本来あるべき方法constがそうではなく、const正しいコードの一部をコンパイルできなかったことがわかりました。私はただ自分constを捨てて乗ることを考えました、しかし私はこれをするために自分自身を連れて行くことができませんでした。
そこで、私はこのメソッドを作成しましたconst。それが他のメソッドを呼び出していることを発見しただけです。これもconstであるはずですが、そうではありませんでした。それで私もそれらを変更しました-ただ発見するために...結局、私はプロジェクトのすべてを探し回って、左右
を追加して数日を費やしました。 同僚は私を笑いました-私が追加したためにコンパイラが発見したバグのいくつかを彼らに示すまでconst
const。興味深いことに、これまで誰も徹底的に調査するために時間をかけたことのないいくつかの長年のバグも、その後は再現できなくなりました。

于 2010-05-19T16:36:01.590 に答える
0

あなたの場合、「怠惰」の答えはおそらく正しいと思いますが、1つのconstキーワードでは、クラスの可変性の詳細を把握するのに十分な表現力がない場合があることを強調したいと思います。

検討:

class MyClass {
public:
    bool operator==(const MyClass &other) const {
        return identity == other.identity;
    }

    void setVisible(bool vis) { gfx.setVisible(vis); }
    bool isVisible() const;

    // other methods ...

private:
    string identity;
    GraphicsData gfx;
}

このコードは妥当だと思います:

MyClass item = ...
item.setVisible(true);

// I want to call a function and be sure that the object's
// visibility did not change, so pass a const ref.
const MyClass &constRef = item;
someSafeFunction(constRef);

しかし同時に、このコードも妥当だと思います。

// Imagine an appropriate std::hash<MyClass> has been
// defined, based on MyClass::identity.
unordered_set<MyClass> set = ...

// Hide some items
for (MyClass &item : set) {
    item.setVisible(false);
}

ただし、コードの2番目のビットはコンパイルされません。これは、その内容への参照unordered_setしか提供できないためです(実際の)。これは、オブジェクトを変更するとハッシュコードが変更され、コンテナ内の場所が無効になる可能性があるためです。const

したがって、事実上、それをunordered_set要求しoperator==const同じアイデンティティの概念を参照しています。しかし、それは私たちが最初のユースケースで望んでいることではありません。

問題は、コードに「オブジェクトが変更されたか」という2つの概念があり、どちらも異なる観点から意味があることです。

constただし、適用できるキーワードは1つしかないため、1つを選択する必要があり、もう1つの場合は問題が発生します。

于 2020-03-28T20:40:01.887 に答える