C++拷贝构造函数

拷贝构造函数是一种重载的构造函数,用于从另一个对象声明和初始化一个对象。

拷贝构造函数有两种类型:

  • 默认拷贝构造函数:编译器定义了默认的拷贝构造函数。如果用户未定义拷贝构造函数,编译器将提供其构造函数。
  • 用户定义的构造函数:程序员定义了用户定义的构造函数。

1.png

用户自定义拷贝构造函数的语法:

 Class_name(const class_name &old_object); 

考虑以下情况:

class A
{
A(A &x) // 拷贝构造函数
{
// 拷贝构造函数
}
}

在上述情况下,可以通过以下方式调用拷贝构造函数:

2.png

让我们看一个拷贝构造函数的简单示例。

// 拷贝构造函数的程序。

#include <iostream>
using namespace std;
class A
{
public:
int x;
A(int a) // 带参数的构造函数
{
x=a;
}
A(A &i) // 拷贝构造函数
{
x = i.x;
}
};
int main()
{
A a1(20); // 调用带参数的构造函数
A a2(a1); // 调用拷贝构造函数
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 << "a的值为: " <<a<< std::endl;
std::cout << "b的值为: " <<b<< std::endl;
std::cout << "*p的值为: " <<*p<< std::endl;
}
};
int main()
{
Demo d1;
d1.setdata(4,5,7);
Demo d2 = d1;
d2.showdata();
return 0;
}

输出:

a的值为: 4
b的值为: 5
*p的值为: 7 

3.png

在上述情况下,程序员未定义任何构造函数,因此语句Demo d2 = d1;调用了编译器定义的默认构造函数。默认构造函数创建现有对象的完全拷贝或浅拷贝。因此,两个对象的指针p指向相同的内存位置。因此,当一个字段的内存被释放时,另一个字段的内存也会自动释放,因为两个字段指向相同的内存位置。用户定义的构造函数解决了这个问题,它创建了深拷贝

深拷贝

深拷贝动态分配了用于副本的内存,然后复制了实际值,源和副本都具有不同的内存位置。这样,源和副本都是不同的,不会共享相同的内存位置。深拷贝要求我们编写用户定义的构造函数。

让我们通过一个简单的示例来理解:

#include <iostream>
using namespace std;
class Demo
{
public:
int a;
int b;
int *p;
cCopy code
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 << "a的值为: " <<a<< std::endl;  
    std::cout << "b的值为: " <<b<< std::endl;  
    std::cout << "*p的值为: " <<*p<< std::endl;  
}  
};
int main()
{
Demo d1;
d1.setdata(4,5,7);
Demo d2 = d1;
d2.showdata();
return 0;
}

输出:

a的值为: 4
b的值为: 5
*p的值为: 7

4.png

在上述情况下,程序员定义了自己的构造函数,因此语句Demo d2 = d1;调用了用户定义的拷贝构造函数。它创建了值类型数据和指针p指向的对象的精确副本。深拷贝不会创建引用类型变量的副本。

拷贝构造函数和赋值运算符(=)之间的区别

拷贝构造函数赋值运算符
它是一个重载的构造函数。它是一个按位运算符。
它用现有对象初始化新对象。它将一个对象的值赋给另一个对象。
拷贝构造函数的语法: Class_name(const class_name &object_name) { // 构造函数的实现。 }赋值运算符的语法: Class_name a, b; b = a;
当使用现有对象初始化新对象时,会调用拷贝构造函数。 对象作为参数传递给函数。 它返回对象。当我们将现有对象赋给新对象时,会调用赋值运算符。
现有对象和新对象共享不同的内存位置。现有对象和新对象共享相同的内存位置。
如果程序员未定义拷贝构造函数,编译器会自动生成隐式默认的拷贝构造函数。如果我们不重载"="运算符,将会发生按位复制。

标签: C++语言, C++语言教程, C++语言技术, C++语言学习, C++语言学习教程, C++语言下载, C++语言开发, C++语言入门教程, C++语言进阶教程, C++语言高级教程, C++语言面试题, C++语言笔试题, C++语言编程思想