7

我当前的实现使用大量具有这种语法的复制构造函数

MyClass::Myclass(Myclass* my_class)

它真的(功能上)不同于

MyClass::MyClass(const MyClass& my_class)

为什么?

我被告知第一个解决方案不是真正的复制构造函数。然而,做出改变意味着相当多的重构。

谢谢!!!

4

5 回答 5

19

不同的是,第一个不是复制构造函数,而是转换构造函数。它从 a 转换MyClass*为 a MyClass

根据定义,复制构造函数具有以下签名之一:

MyClass(MyClass& my_class)
MyClass(const MyClass& my_class)
//....
//combination of cv-qualifiers and other arguments that have default values

12.8. 复制类对象

2) 类 X 的非模板构造函数是复制构造函数,如果它的第一个参数是 X&、const X&、volatile X& 或 const volatile X& 类型,并且没有其他参数或者所有其他参数都有默认参数 (8.3 .6).113) [ 示例:X::X(const X&) 和 X::X(X&,int=1) 是复制构造函数。

编辑:你似乎混淆了两者。

假设你有:

struct A
{
   A();
   A(A* other);
   A(const A& other);
};

A a;     //uses default constructor
A b(a);  //uses copy constructor
A c(&a); //uses conversion constructor

它们共同服务于不同的目的。

于 2012-10-02T10:54:10.380 回答
8

第一个版本不是复制构造函数。就那么简单。它只是另一个构造函数。

类的复制构造函数X必须具有签名(X &, ...)or(X const &, ...)(X volatile &, ...)or (X const volatile &, ...),其中除第一个参数之外的所有参数都具有默认值(如果它们存在)(并且它不能是模板)。


也就是说,你应该非常仔细地思考为什么你违反了零规则:大多数设计良好的类根本不应该有任何用户定义的复制构造函数、复制赋值运算符或析构函数,而是依赖于良好的- 设计的成员。您当前的构造函数采用指针这一事实让我想知道您的代码是否正确运行,例如MyClass x = y;- 值得检查。

于 2012-10-02T10:55:06.880 回答
6

某些语言结构需要复制构造函数:

  • 按值传递
  • 按值返回
  • 复制样式初始化(​​尽管在这种情况下通常会省略复制)

如果语言要求复制,并且您提供了复制构造函数,则可以使用它(当然,假设 cv-qualifications 是可以的)。

由于您没有提供复制构造函数,因此您将获得编译器生成的复制构造函数。这通过复制每个数据成员来工作,即使这对您的班级来说不是正确的做法。例如,如果您的 not-a-copy-constructor 显式地执行任何深层复制或分配资源,那么您需要禁止编译器生成的副本。

如果编译器生成的副本适用于您的类,那么您的非副本构造函数基本上是无害的。不过,我认为这不是一个特别好的主意:

void some_function(const MyClass &foo);

MyClass *ptr = new MyClass();
const MyClass *ptr2 = ptr;
some_function(ptr); // compiles, but copies *ptr and uses the copy
MyClass bar(ptr2);  // doesn't compile -- requires pointer-to-non-const

即使假设编译器生成的副本对您的类没有好处,进行必要的更改也不需要大量的重构。假设您的非构造函数实际上并未修改其参数指向的对象,因此在修复签名后,您将拥有:

MyClass::MyClass(const MyClass* my_class) {
    // maybe treat null pointer specially
    // do stuff here
}

你需要:

MyClass::MyClass(const MyClass& my_class) {
    do_stuff(my_class);
}

MyClass::MyClass(const MyClass* my_class) {
    // maybe treat null pointer specially
    do_stuff(*my_class);
}

MyClass::do_stuff(const MyClass& my_class) {
    // do stuff here
}

您还需要将任何初始值设定项列表从旧构造函数复制到新构造函数,并对其进行修改以使其my_class不是新构造函数中的指针。

删除旧的构造函数可能需要大量重构,因为您必须编辑任何使用它的代码。不过,您不必删除旧的构造函数来修复默认复制构造函数的任何问题。

于 2012-10-02T11:21:10.467 回答
2

为什么我要使用复制构造函数而不是转换构造函数?

如果您将MyClass对象提供给一些期望您的复制构造函数有效的代码,则可能会出现问题。

STL 容器就是这种情况。例如,如果您使用 a std::vector<MyClass>,则必须知道向量可以使用其复制构造函数来移动元素以进行重新分配。

编译器提供的默认构造函数将执行浅拷贝,调用每个属性的拷贝构造函数,为指针等基类型制作简单的拷贝。如果你想要某种形式的深拷贝,你将不得不正确地重写拷贝构造函数MyClass

于 2012-10-02T11:12:00.337 回答
2

第一个示例不是复制构造函数。这意味着当您提供它时,编译器仍然为您提供一个默认的复制构造函数,其签名等效于

MyClass(const MyClass& my_class);

如果你对你的构造函数做了一些特殊的事情,并且编译器提供的复制构造函数不遵循这个逻辑,你应该实现一个复制构造函数或者找到一种方法来禁用它。

于 2012-10-02T10:57:39.707 回答