看下面段例子 从网上找了一个例子
//```cpp
#include <stdio.h>
#include <iostream>
using namespace std;
class Person
{
public:
Person(){ cout << "构造函数" << endl; }
Person(const Person& p)
{
cout << "Copy Constructor" << endl;
}
Person& operator=(const Person& p)
{
cout << "Assign" << endl;
return *this;
}
private:
int age;
string name;
};
void f(Person p)
{
return;
}
Person f1()
{
Person p;
return p;
}
int main()
{
Person p;
Person p1 = p; // 1 调用拷贝构造函数
Person p2;
p2 = p; // 2 调用赋值拷贝
f(p2); // 3 调用拷贝构造函数
p2 = f1(); // 4 先是调用f1() 拷贝构造因为传递回来的是值传递会创建一个临时变量(tempObjet = f1()) 之后再调用赋值拷贝给p2
Person p3 = f1();
// 5 按照4的解释,应该是首先调用拷贝构造函数创建临时对象;然后再调用拷贝构造函数使用刚才创建的临时对象创建新的对象p3,也就是会调用两次拷贝构造函数。不过,编译器也没有那么傻,应该是直接调用拷贝构造函数使用返回值创建了对象p3。
getchar();
return 0;
}
``
关于调用拷贝构造函数的时机:
- 当形参中以值传递的形式传递的时候,因为会创建一个临时对象( person p = p 这样的形式)。
- 是当返回值也是按照值传递的时候,因为也是会调用临时对象来创建一个对象因此调用一个拷贝构造函数
- 当拷贝构造函数使用已有的对象创建一个新的对象,赋值运算符是将一个对象的值复制给另一个已存在的对象。区分是调用拷贝构造函数还是赋值运算符,主要是否有新的对象产生。
.
.
关于为什么拷贝构造函数参数要传递引用:
其实最主要的还是为了不使得参数传递的时候无限制调用拷贝构造,因为如果按照值参数传递的形式的话肯定会再调用拷贝构造函数的(当形参中以值传递的形式传递的时候,因为会创建一个临时对象( person p = p 这样的形式调用拷贝构造)这样就无穷调用了。
.
而对于赋值拷贝为什么要使用引用:
因为直接值传递会调用一次拷贝构造但不会无限递归下去,所以也就是从效率方面进行考虑了。
.
关于深拷贝浅拷贝
其实主要是指针的问题。当拷贝指针的时候默认的拷贝只会拷贝指针的值而不是指向的对象的内存中的值。因此需要自己重载拷贝构造函数。
而对于赋值运算符来说 也是同样存在这样的问题的原生的比如 s1 = s2 如果两个都是都是指针的话只会是指向同一个内存地址。因此要重载重新定义深拷贝。
.
.
总结:
拷贝构造函数和赋值运算符的行为比较相似,却产生不同的结果;拷贝构造函数使用已有的对象创建一个新的对象,赋值运算符是将一个对象的值复制给另一个已存在的对象。区分是调用拷贝构造函数还是赋值运算符,主要是否有新的对象产生。
关于深拷贝和浅拷贝。当类有指针成员或有动态分配空间,都应实现自定义的拷贝构造函数。提供了拷贝构造函数,最后也实现赋值运算符。