7

次の問題があります。

私はこれを行うべきクラスを持っています:

Obj o;
Obj o1(o), o1=o; // deep-copies
const Obj c(o), c=o; // deep-copies
const Obj c1(c), c1=c; // shallow-copies
Obj o2(c), o2=c; // deep-copies

継承なしでこれを行うにはどうすればよいですか? (つまり、そうでなければConst_obj継承しObjます。)

編集:

直接使用o.clone()することはオプションではありません。誤ってクローンを作成しないと、簡単にバグが発生する可能性があるからです。

編集:

最後に、Scott Meyers による効果的な C++のアイデアを使用した遅延評価による適切で完全なソリューションがあります。以下の私の答えをチェックしてください。

4

3 に答える 3

4

いいえ、できません。

  • コンストラクターは cv 修飾できないため、強制的に const オブジェクトを構築することはできません。
  • 関数の戻り値の型 (演算子を含む) はそのシグネチャの一部ではないため、戻り値の型を変更するだけで関数をオーバーロードすることはできません。

また、可能であれば、本当に混乱するでしょう。ニーズに合ったメソッドを作成し、明確な名前を付けてください。

于 2012-11-12T12:33:58.313 に答える
2

Scott Meyers による効果的な C++ を読んだ後、次の解決策があります。

遅延評価 (参照カウント付き) を行うテンプレートを定義します。

class Obj : private lazy<Obj_data>{};

怠惰な人は Obj_data を非公開で保存し、アクセサーを保護し、1 つは変更用、もう 1 つは読み取り専用アクセス用です。
修飾子アクセサーは、必要に応じて最初に をディープ コピーしObj_data、次にデータへの参照を渡します。読み取り専用アクセサーは const 参照を返すだけです。

これの全体的なコストは、2 つの余分なポインター (データ用に 1 つとカウンター用に 1 つ) とカウンターを格納することです。

実装は次のようなものです。

class lazy{
protected:
  lazy(const lazy&obj){lazy_copy(obj);}
  //(the required constructors, operator= ...)

  // accessors:
  const Obj_data& data() const {return *od;}
  Obj_data& mod_data() {make_private(); return *od;}
private:
  void lazy_copy(const lazy& obj);
  void make_private(); // this does the actual deep-copy, as late as possible.
private:
  counter*;
  Obj_data* od;
};

したがって、 go の属性の読み取りとObj変更

void Obj::method(){
   cout << data().some_attribute;    // simple read
   mod_data().i = 10;                // simple modify
   const Obj_data& const_d = data(); // assignable for lots of read-outs
   Obj_data& var_d = mod_data();     // assignable for lots of modifications.
}

クラスの非 const 関数としてのみメンバーdata()で使用できることに注意してください。したがって、このソリューションはオーバーヘッドがほとんどなく、完全に安全です。constmod_data()

理論的背景: 質問の望ましい動作は実装の詳細であり、クライアントには関係ありません。したがって、プライベート継承で解決します。

于 2012-11-14T17:35:07.207 に答える
0

部分的には、仮引数を使用して次のことができます。

class C {
public:
    struct NonStandardCopy { };

    C (const C &) {
        // "ordinary" copy constructor with default behavior
    }

    C (const C &, NonStandardCopy) {
        // "other" "copy" constructor
    }
};

C c = c1; // default
C c (c1); // default
C c (c1, C::NonStandardCopy ()); // non-default

編集:クローンのみのアプローチは、あなたが望むものかもしれません(移動セマンティクスと一緒に、パフォーマンスヒットはあまり大きくないかもしれません):

class C {
private:
    struct DeepCopy { };
    struct ShallowCopy { };

    C (const C &) = delete;

    C (const C &, DeepCopy) {
        // deep copy
    }

    C (const C &, ShallowCopy) {
        // shallow copy
    }
public:
    // move constructor
    C (C && other) = default;

    const C clone () const { // 1
        // shallow copy
        return C (*this, ShallowCopy ());
    }

    C cloneToNonConst () const {  // 2
        // deep copy
        return C (*this, DeepCopy ());
    }

    C clone () { // 3
        return cloneToNonConst ();
    }
};

C o;
C o1 = o.clone (); // call 3
const C o2 = o1.clone (); // call 3
const C o3 = o2.clone (); // call 1
C c4 = o3.cloneToNonConst (); // call 2; o3.clone () will give error
于 2012-11-12T12:39:28.290 に答える