2016-09-12 5 views
0

OOPで公開されている方法の1つの役割は、オブジェクトが常に有効な状態になっていることを確認することです(これは、ポッドの種類がmemcpyではないという重要な理由の1つです)。例えば。非常に基本的な、知識をひけらかす例:(/ javaのようなセットを無視して取得してください):この例ではオブジェクトのスライシングがカプセル化を中断しますか?

class Restricted { 
protected: 
    int a; 

public: 
    Restricted() : a{0} {} 

    // always returns a non-negative number 
    auto get() const -> int { 
    return a; 
    } 

    auto set(int pa) -> void { 
    if (pa < 0) 
     a = 0; 
    else 
     a = pa; 
    } 

    auto do_something() { 
    // here I code with the assumption that 
    // a is not negative 
    } 
}; 

は、クラスRestrictedRestrictedオブジェクトは常に非負の数を保持しているようにモデル化されています。これは私がRestrictedの有効な状態を定義する方法です。インタフェースを見ると、Restricted ::getは常に負でない数値を返すと言えます。ユーザーがRestrictedに負の数を保持させる方法はありません。

aは、オプションで簡単にクラスを拡張できるように保護されています。だから、私たちはすべての数字を可能にするタイプでRestrictedを拡張してみましょう:一見

class Extended : public Restricted { 
public: 
    Extended() { a = -1; } 

    auto set(int pa) -> void { 
    a = pa; 
    } 

    auto do_something() { 
    // now a can be negative, so I take that into account 
    } 
}; 

すべてはokです。 ExtendedRestrictedまたはその動作を変更しません。 Restrictedは依然として同じで、負の数を許容する別のタイプを追加するだけです。

Restrictedの私たちの最初の仮定はもはや保持しません。

Restricted r = Extended{}; 

// or 

Extended e; 
e.set(-24); 

Restricted r = e; 

// and then: 

r.do_something(); // oups 

何かがアップ追加しない:

C++が警告なしオブジェクトスライスを使用できますので、ユーザは容易に負の数(無効な状態にあるオブジェクト)を保持Restrictedオブジェクトを取得することができ

  • RestrictedのサブクラスとしてExtendedを作成するのは間違っていましたか?もしそうなら、なぜですか?
  • aprotectedと設定するのは間違っていましたか?どうして? protectedは、自分のクラスでの動作の変更を許可すべきではありません。
  • C++でオブジェクトをスライスするのは間違っていますか?他
  • 上記のすべてのもの
+3

まあ、それはクラスの設計者次第です。基本クラスにパブリックコピーコンストラクタがある場合は、コピー可能であると考えられます。そうでなければ、保護されたコピーコンストラクタを持っています。 –

+0

あるいは 'a'を' unsigned int'と宣言できます。拡張コンパイル時にコンパイル時の警告が表示されます。 – Ceros

+0

@KerrekSBコピー可能にしたいとしましょう。私はまだ、負の数を保持する基本クラス型のオブジェクトを持つことを期待していません。 – bolov

答えて

6

私はいつも非負であることを期待すれば、保護されたものとして設定するのは間違っていましたか?どうして?

はい、間違っています。Restrictedのインターフェイスにはがあり、aは負でない必要があります。それは型が設定する不変量です。また、派生クラスがその不変量をオーバーライドできるようにする関数はvirtualではありません。

virtualファンクションが不明瞭で不変なので、ExtendedはOOPの基本ルールを破っています。派生クラスのインスタンスは、(パブリック)ベースクラスのインスタンスのように扱うことができます。それはスライスを意味するものではありません。つまり、Extendedをポインタ/参照をRestrictedに渡す関数に渡すことができ、すべてがExtendedと話しているかのように動作するはずです。

ExtendedをRestrictedのサブクラスとして作成するのは間違っていましたか?もしそうなら、なぜですか?

それはに間違っていた:

  1. aprotectedの代わりprivateしてください。

  2. Restrictedのインターフェイスをvirtualにする。

それは間違っているC++オブジェクト・スライシングを許可するためのものですか?

1

C++を使用すると、同時に同じ時間に、あなたの足の両方を撮影することができ銃を与えます。これは常にそうであった。

このような状況が発生しないようにするには、ベースクラスのコピーコンストラクタを削除し、派生クラスのコピーコンストラクタでベースクラスのコピーを処理します。

また、プライベート継承を使用することもできます。

クラス設計の要件を満たすためには、最適なソリューションを選択する必要があります。

+0

これはC++関連ではないので、基本的にどのOOP言語でも 'protected'というフィールドを作ることができます。これは"任意の派生クラスが自由にそれを変更できる "ことを意味します。そして何らかの理由でOPは、フィールドを「保護されている」とすると、それが変更されるべきではないと考えています。 – Groo

+1

OPはそれを防ぐ方法を知りたくありません。おそらく、彼はすでにそうしています。 OPは彼の推論のラインで哲学的な問題を知りたい。ニコール・ボラスの答えは、はるかに質問された質問のラインです。 – jaggedSpire

+0

@jaggedSpire ty、あなたにスポットがあります。 – bolov

関連する問題