我可以为const和非const实例编写不同的copyCtor吗?

时间:2012-11-12 12:29:16

标签: c++ copy-constructor deep-copy shallow-copy

我有以下问题:

我有一个应该这样做的课:

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_objObj继承。)

编辑:

直接使用o.clone()不是一个选项,因为我可以轻易地通过而不是克隆来引入错误。

编辑:

最后,使用来自Scott Meyers的 Effective C ++ 的想法,有一个适当的,完整的解决方案和惰性评估。看看下面的答案。

3 个答案:

答案 0 :(得分:4)

不,你不能。

  • 构造函数不能是cv限定的,因此不能强制它构造const对象。
  • 函数的返回类型(包括运算符)不是它的签名的一部分,因此只需更改它的返回类型就不能重载函数。

此外,如果有可能,我会发现真的令人困惑。只需制作适合您需求的方法,并以明确的方式命名。

答案 1 :(得分: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;
};

因此,阅读和修改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()是该类中的非const函数,因此此解决方案完全安全且开销很小。

理论背景:问题中所需的行为是一个实现细节,与客户无关。因此我们通过私有继承解决它。

答案 2 :(得分: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