C++ 拷贝构造函数
拷贝构造函数是一个 重载 的构造函数,用于从另一个对象声明和初始化一个对象。
拷贝构造函数有两种类型
- 默认拷贝构造函数: 编译器定义了默认的拷贝构造函数。如果用户没有定义拷贝构造函数,编译器会提供默认的构造函数。
- 用户自定义构造函数: 程序员定义了用户自定义的构造函数。
用户自定义复制构造函数的语法
Class_name(const class_name &old_object);
考虑以下情况:
class A
{
A(A &x) // copy constructor.
{
// copyconstructor.
}
}
在上述情况下,
可以通过以下方式调用复制构造函数:
让我们看一个拷贝构造函数的简单示例。
// 拷贝构造函数的程序。
#include <iostream>
using namespace std;
class A
{
public:
int x;
A(int a) // parameterized constructor.
{
x=a;
}
A(A &i) // copy constructor
{
x = i.x;
}
};
int main()
{
A a1(20); // Calling the parameterized constructor.
A a2(a1); // Calling the copy constructor.
cout<<a2.x;
return 0;
}
输出:
20
当调用复制构造函数时
复制构造函数在以下情况下被调用:
- 当我们用同一类别的另一个现有对象初始化对象时。例如,Student s1 = s2,其中Student是类别。
- 当同一类别的对象以按值方式作为参数传递时。
- 当函数通过按值方式返回同一类别的对象时。
构造函数产生两种类型的拷贝
- 浅拷贝
- 深拷贝
浅拷贝
- 默认的复制构造函数只能产生浅拷贝。
- 浅拷贝被定义为通过复制所有成员变量的数据来创建对象的过程。
让我们通过一个简单的例子来理解:
#include <iostream>
using namespace std;
class Demo
{
int a;
int b;
int *p;
public:
Demo()
{
p=new int;
}
void setdata(int x,int y,int z)
{
a=x;
b=y;
*p=z;
}
void showdata()
{
std::cout << "value of a is : " <<a<< std::endl;
std::cout << "value of b is : " <<b<< std::endl;
std::cout << "value of *p is : " <<*p<< std::endl;
}
};
int main()
{
Demo d1;
d1.setdata(4,5,7);
Demo d2 = d1;
d2.showdata();
return 0;
}
输出:
value of a is : 4
value of b is : 5
value of *p is : 7
在上述情况下,程序员没有定义任何构造函数,因此,语句 Demo d2 = d1; 调用了编译器定义的默认构造函数。默认构造函数创建了现有对象的精确副本或浅拷贝。因此,两个对象的指针p都指向相同的内存位置。因此,当一个字段的内存被释放时,另一个字段的内存也会自动被释放,因为两个字段都指向同一个内存位置。这个问题通过 用户定义的构造函数 来解决,该构造函数创建了 深拷贝 。
深拷贝
深拷贝动态分配了副本的内存,然后复制了实际值,源对象和副本都有不同的内存位置。这样,源对象和副本是不同的,不会共享同一内存位置。深拷贝要求我们编写用户定义的构造函数。
让我们通过一个简单的例子来理解。
#include <iostream>
using namespace std;
class Demo
{
public:
int a;
int b;
int *p;
Demo()
{
p=new int;
}
Demo(Demo &d)
{
a = d.a;
b = d.b;
p = new int;
*p = *(d.p);
}
void setdata(int x,int y,int z)
{
a=x;
b=y;
*p=z;
}
void showdata()
{
std::cout << "value of a is : " <<a<< std::endl;
std::cout << "value of b is : " <<b<< std::endl;
std::cout << "value of *p is : " <<*p<< std::endl;
}
};
int main()
{
Demo d1;
d1.setdata(4,5,7);
Demo d2 = d1;
d2.showdata();
return 0;
}
输出:
value of a is : 4
value of b is : 5
value of *p is : 7
复制构造函数和赋值操作符(=)的区别
复制构造函数 | 赋值运算符 |
---|---|
这是一个重载的构造函数。 | 这是一个位运算符。 |
它使用已有对象初始化新对象。 | 它将一个对象的值赋给另一个对象。 |
复制构造函数的语法: Class_name(const class_name &object_name) { // 构造函数的内容 } | 赋值运算符的语法: Class_name a,b; b = a; |
复制构造函数 在用已有对象初始化新对象时被调用。 对象作为参数传递给函数。 它返回对象。 |
赋值运算符 在将已有对象赋给新对象时被调用。 |
现有对象和新对象共享不同的内存位置。 | 现有对象和新对象共享相同的内存位置。 |
如果程序员没有定义复制构造函数,编译器将自动生成隐式的默认复制构造函数。 | 如果我们没有重载“=”运算符,将发生位复制。 |