张掖市网站建设_网站建设公司_响应式开发_seo优化
2026/1/17 3:44:14 网站建设 项目流程
四、拷贝构造函数

如果一个构造函数的第⼀个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数。

拷贝构造使用于当前类型的对象去初始化当前类型的另一个要创建的对象,换句话来说就是当你完成的是自身这个类型的拷贝初始化就会用拷贝构造,拷贝构造函数是构造函数的一个重载。

拷贝构造函数的特点:

  1. 拷贝构造函数是构造函数的⼀个重载。
  2. 拷贝构造函数的第⼀个参数必须是当前类类型对象的引用,使用传值方式编译器直接报错,因为语法逻辑上会引发无穷递归调用。 拷贝构造函数也可以多个参数,但是第⼀个参数必须是类类型对象的引用,后面的参数必须有缺省值。
  3. C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。
  4. 若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。

既然拷贝构造函数是构造函数的一个重载,接下来,我们来写一个拷贝构造函数:

代码语言:javascript

AI代码解释

class Date { public: Date(int year = 1, int month = 1, int day = 1) { _year = year; _month = month; _day =day; } ~Date() { cout << "~Date()" << endl; } Date(Date& d) { _year = d._year; _month = d._month; _day = d._day; } void Print() { cout << _year << "/" << _month << "/" << _day<<endl; } private: int _year; int _month; int _day; }; int main() { Date d1(2025,8,4); Date d2(d1);//拷贝构造 d2.Print(); return 0; }

我们看到,在拷贝构造特点中的第二点中写到:拷贝构造函数的第⼀个参数必须是类类型对象的引用。

那为什么要用引用传参?为什么不能用传值传参?

有人会说,func(d1)不是在调用函数吗?怎么跑到拷贝构造上面去了 ?在调用一个函数前,编译器会先完成传参(传值传参就是拷贝,对于自定义类型的拷贝,都是调用拷贝构造来完成拷贝的),然后再去调用这个函数

总结:C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。

如果拷贝构造函数使用传值调用,会形成无穷递归:

每次要调用靠别构造函数之前要进行传值传参,传值传参是一种拷贝,又形成一个新的拷贝构造,调用新的拷贝构造之前要进行传值传参,传值传参是一种拷贝,又形成一个新的拷贝构造,以此下去,就形成了无穷递归,但是当我们使用引用传参时,就不需要进行拷贝构造,这样就不会形成无穷递归了,所以我们使用引用传参。

当我们使用拷贝构造函数的时候,引用传参建议使用const:

代码语言:javascript

AI代码解释

class Date { public: Date(int year = 1, int month = 1, int day = 1) { _year = year; _month = month; _day =day; } ~Date() { cout << "~Date()" << endl; } //加上const可以避免权限放大 Date(const Date& d) { _year = d._year; _month = d._month; _day = d._day; } void Print() { cout << _year << "/" << _month << "/" << _day<<endl; } private: int _year; int _month; int _day; }; void func(Date d) { } int main() { Date d1(2025,8,4); func(d1); return 0; }

通过上面的学习,我们知道拷贝构造函数是适用于当前类型的对象去初始化当前类型的另一个要创建的对象,比如上面的Date类,那如果说拷贝构造仅仅适用于这种一一拷贝,那拷贝构造是不是有点太简单了。接下来,我们来看一下稍微难点的应用:

代码语言:javascript

AI代码解释

class Stack { public: Stack(int n=4) { _a = (int*)malloc(sizeof(int) * n); _top = 0; _capacity = n; } ~Stack() { if (_a) { free(_a); _a = nullptr; _top = 0; _capacity = 0; } } Stack(const Stack& s) { _a = s._a; _top = s._top; _capacity = s._capacity; } private: int* _a; int _top; int _capacity; }; int main() { Stack s1; Stack s2(s1); return 0; }

ok,我们创建了一个栈,然后使用拷贝构造函数给s2进行初始化,在这个初始化的过程中会发生什么不可预期的东西呢?

我们看到红方框内的地址是一样的。那就有同学会问了,地址一样会有什么问题吗?ok,当你使用编译器进行调试的时候,就会发现编译器崩了:

这是什么原因呢?当我们调试编译器的时候,返现拷贝构造时没有发生任何错误,但是当我们执行到第二次析构函数的时候,此时发生了报错,只是因为编译器对空间进行了两次释放(同一块空间)

那为什么会对空间进行两次释放呢?

那我们该如何解决呢?对于这种情况,我们要使用深拷贝:不仅仅是对成员拷贝,还是对指向资源空间数据进行拷贝

代码语言:javascript

AI代码解释

class Stack { public: Stack(int n=4) { _a = (int*)malloc(sizeof(int) * n); _top = 0; _capacity = n; } ~Stack() { if (_a) { free(_a); _a = nullptr; _top = 0; _capacity = 0; } } //深拷贝 Stack(const Stack& s) { _a = (int*)malloc(sizeof(int) * s._capacity); if (_a == nullptr) { perror("malloc fail!"); exit(1); } //将数据拷贝过去 memcpy(_a,s._a,sizeof(int)* s._capacity); _top = s._top; _capacity = s._capacity; } private: int* _a; int _top; int _capacity; }; int main() { Stack s1; Stack s2(s1); return 0; }

前面我们学习的构造函数和析构函数,当我们不写时,编译器自动生成的构造函数和析构函数对内置类型成员不做处理,自定类型成员会调用他的析构函数。但是拷贝构造有点不同:若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。

www.dongchedi.com/article/7596039640361206334
www.dongchedi.com/article/7596036566536520217
www.dongchedi.com/article/7596038202335707673
www.dongchedi.com/article/7596036203376919065
www.dongchedi.com/article/7596036558738833982
www.dongchedi.com/article/7596037454990426648
www.dongchedi.com/article/7596035720197227033
www.dongchedi.com/article/7596037630450565657
www.dongchedi.com/article/7596035789235307032
www.dongchedi.com/article/7596035144272740888
www.dongchedi.com/article/7596035023862596121
www.dongchedi.com/article/7596035565267993112
www.dongchedi.com/article/7596034656816972312
www.dongchedi.com/article/7596035038500733464
www.dongchedi.com/article/7596035446715597374
www.dongchedi.com/article/7596033910857925144
www.dongchedi.com/article/7596032917361951257
www.dongchedi.com/article/7596033810694160921
www.dongchedi.com/article/7596034317558628926
www.dongchedi.com/article/7596026007967416857
www.dongchedi.com/article/7596026266785186366
www.dongchedi.com/article/7596024522248176190
www.dongchedi.com/article/7596024522244014654
www.dongchedi.com/article/7596024000137380377
www.dongchedi.com/article/7596010701236306456
www.dongchedi.com/article/7596012418107556414
www.dongchedi.com/article/7595895683039887897

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询