如何在C++中同时使用默认和自定义拷贝构造函数?

12

我有一个数据成员很多的长类。我想为它编写一个复制构造函数。但是,如果我编写了自己的复制构造函数,我将失去对默认复制构造函数的访问。

我只想在我的复制构造函数中修复几个指针。因此,我想要对象的浅拷贝,这可以通过默认的复制构造函数完成。

当我有自己的复制构造函数时,有可能访问默认的复制构造函数吗?


1
其他代码如何知道调用默认构造函数还是你的构造函数? - mmmmmm
@Mark,据我理解,OP想要在自己的构造函数中仅使用默认构造函数。 - Rost
@Mark:当然是我的复制构造函数。在调用我的复制构造函数之前,我只想要对象的浅层复制。稍后我可以执行自己的复制/修复操作。 - pablo
你能否提供一些简短的示例代码,说明在复制构造函数中调用默认构造函数的好处? - juanchopanza
@juanchopanza:好处很明显。我有一个对象的浅拷贝,而且不需要自己手动实现。 - pablo
@pablo bot 你不是会得到浅拷贝吗? - juanchopanza
8个回答

13

将您不想更改的内容包装在一个struct中,并从其派生(私有)。 在您的复制构造函数中,只需调用基类的复制构造函数。


我唯一不喜欢它的地方在于,它支持提问者在可能是愚蠢的情况下:将需要特殊处理的“少量”指针放在一个单独的类中。不过,它确实做到了被要求做的事情。 - Steve Jessop
1
@SteveJessop 可能还有其他批评意见。例如,有一个足够多成员的类就会成为问题。至于指针...如果不知道它们为什么需要特殊处理,很难确定,但是,如果这是动态分配对象和深度拷贝的问题,那么任何一个类中超过一个指针都会引起问题。 - James Kanze

8

不,你不能同时拥有默认的和自己的复制构造函数。

但是有两种解决这个问题的方法:


1 将指针封装在具有定义复制语义的类中

例如:

class A {
public:
private:
   int trivial1;
   int trivial2;
   ...
   SomePointer  nontrivialMember;
};

class SomePointer {
public:
  SomePointer(const SomePointer&); // here the non trivial part of A copy semantics
  int* nonTrivialMember;
};

2将琐碎的参数封装在一些琐碎的结构中。

示例:

class A {
public:
   A(const A& o) : data(o.data) {
     // non trivial part
   }
private:
   struct Data {
     int trivial1;
     int trivial2;
     ...
   } data;
   int* nontrivialMember;
};

我总是会选择第一种解决方案。

[更新]

还有第三种解决方案,与我的第二种解决方案非常相似,将你的琐碎部分封装在私有继承的基类中。但我仍然更喜欢第一种解决方案。


1
那么选择第一种解决方案的动机是什么? - user877329
2
@user877329 选择第一种方案的主要原因是只实现必要的复制/移动语义。我所说的必要是指编译器本身无法定义的语义。在第一种解决方案中,您只需处理指针即可。在其他解决方案中,您还必须复制该类的这个微不足道的部分。 - PiotrNycz

4

最简单的方法是将指针封装到类中,并在它们的复制构造函数中手动执行“修复”,然后您可以愉快地使用默认的复制构造函数。


0

你可以选择默认功能或自定义功能,但不能同时使用两者。如果你想为不同的对象选择不同的功能,你应该编写一个成员函数来处理这种情况。

void DeepCopy(MyClass* rhs);

例如。

0

如果您创建了自己的默认复制构造函数,则无法访问它 - 编译器不会生成它。但是有一个解决方法 - 将类分成数据结构和逻辑。

请参见以下示例:

struct Data
{
  int i;
  std::string s;

  Data(): i(), s() {}
};

class Code: private Data
{
public:

  Code() {}

  Code(const Code& rhs): Data(rhs) // Call default copy ctor
  {
     i = 42; // Your copy part
     return *this;
  }

};

0
我的解决方案是使用简单的memcpy()而不是调用隐式(编译器生成的)复制构造函数,如下面的示例所示:
Class Foo
{
public:
   ...
   Foo (Foo & other) {
      // copies trivial part (and non-trivial part with possible wrong values)
      memcpy(this, &other, sizeof(Foo));

      // your non-trivial part here, overwrites the wrong values (if any) above.
   }
}

然而,这种副作用是memcpy()也会复制那些非平凡的部分,这是一种浪费。如果非平凡的部分不包含太多空间,我更喜欢我的解决方案。

例如,像下面这样的一个类只浪费了一个指针的4字节复制,假设指针的大小为4字节。

Class Bar
{
    int x, y, z;

    // memcpy() wastes these 4 bytes copy,
    // since actual copy constructor wants a new string
    string *s;  
}

0

不,无法从用户定义的复制构造函数中调用默认的复制构造函数。


0

这对我有用...(C++11,不确定它是否适用于旧的std) 不确定为什么它不会陷入无限循环。

class Foo {
public:
  Foo(const Foo &orig) {
     *this = orig;
     ... exchange pointers, do own stuff
  }

它不会陷入无限循环,因为 *this = orig 调用的是复制赋值运算符,而不是复制构造函数。 - bolov
请参考https://dev59.com/73E85IYBdhLWcg3wvGAR,了解有关此方法的想法。 - bolov
有道理,谢谢链接!尽管提到了缺点,但我支持这个优点,但这确实取决于类别... - chhu79

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接