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的 Effective C++ 中的思想,有一个适当的、完整的解决方案,其中包含惰性求值。在下面查看我的答案。

4

3 回答 3

4

不,你不能。

  • 构造函数不能是 cv 限定的,所以你不能强制它构造一个 const 对象。
  • 函数的返回类型(包括运算符)不是其签名的一部分,因此您不能仅通过更改函数的返回类型来重载函数。

另外,如果可能的话,我会觉得这真的很令人困惑。只需制作适合您需要的方法,并以明确的方式命名它们。

于 2012-11-12T12:33:58.313 回答
2

在阅读Scott Meyers的 Effective C++ 之后,以下是一个解决方案:

定义一个执行惰性评估的模板(使用引用计数):

class Obj : private lazy<Obj_data>{};

并且惰性存储 Obj_data 私有,具有受保护的访问器,一个用于修改,一个用于只读访问。
如果需要,修饰符访问器首先对数据进行深度复制Obj_data,然后移交对数据的引用。只读访问器只返回一个 const 引用。

这样做的总成本是存储 2 个额外的指针(一个用于数据,一个用于计数器)和一个计数器。

实现是这样的:

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;
};

因此,读取和修改 gos 的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.
}

请注意,您只能data()const成员用作mod_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 回答