目录
一:前言
本片博客为大家讲解构造函数|析构函数|拷贝构造函数在c++中的作用。
二:默认成员函数
类中有六个默认成员函数:
我们一一来学习这些成员函数。
如果我们需要初始化,构造函数会给我们带来意想不到的结果。
清理也一样,析构函数就很good。
三:构造函数
一:构造函数概念
构造函数 :是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
构造函数是i特殊的成员函数,需要注意的是构造函数虽然名称叫构造,但构造函数的主要对象不是开空间创造对象,而是初始化对象。
二:构造函数的特性
- 函数名与类名相同。
- 无返回值。
- 对象实例化时编译器自动调用对应的构造函数。
- 构造函数可以重载。
三:构造函数实例
古板概念我们就不细细研究了,我们上代码研究,自然而然的就懂了。
代码演示:Date.cpp
class Date { public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } void Print() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; int main() { Date d1; d1.Init(2022, 7, 5); d1.Print(); Date d2; d2.Init(2022, 7, 6); d2.Print(); return 0; }
对于Date类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?
这样子就很麻烦,我们每次传参都要调用函数,所以我们的c++神,本贾尼大佬,就创造了构造函数,我们不调用,直接给赋值。
代码演示:(带参构造)
#include<iostream> using namespace std; class Date { public: Date(int year, int month, int day) { _year = year; _month = month; _day = day; } void Print() { cout << _year << "年" << _month << "月" << _day <<"日" << endl; } private: int _year; int _month; int _day; }; int main() { Date d1(1998,10,2); d1.Print(); Date d2(1996,12,3); d2.Print(); return 0; }
终端显示:
这样子就很完美,我们不用在写初始化函数,我们每次直接在类赋值就可以。
如图这是一个带参构造。我展示无参构造。
代码演示:
class Date { public: Date() { _year = 1; _month = 0; _day = 1; } Date(int year , int month , int day ) { _year = year; _month = month; _day = day; } void Print() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; // Date f(); 函数声明 int main() { Date d1; d1.Print(); Date d2(2023, 10, 19); d2.Print(); return 0; }
终端显示:
如上图终端显示:
不给参数就会调用无参构造函数,给参数就会调用带参构造函数。
这个带参构造就是全缺省构造函数,也要记住全缺省的规则,以及半缺省的要求。
四:注意
1:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
int main() { Date d1(); d1.Print(); Date d2(2023, 10, 19); d2.Print(); return 0; }
2:如果你没有定义构造函数,编译器会自动帮助你生产一个无参的默认构造函数
class Date { public: //Date(int year , int month , int day ) //{ // _year = year; // _month = month; // _day = day; //} void Print() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; // Date f(); 函数声明 int main() { Date d1; d1.Print(); return 0; }
终端显示:
五:默认构造函数
无参构造函数,全缺省构造函数,自动生成的构造函数都称为 默认构造函数
并且默认构造函数只能有一个
注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。
class Date { public: Date() { _year = 1; _month = 1; _day = 1; } Date(int year=1999 , int month=2 , int day=2 ) { _year = year; _month = month; _day = day; } void Print() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; // Date f(); 函数声明 int main() { Date d1; d1.Print(); return 0; }
【显示报错】
虽然语法上允许他们存在,但是到编译器去调用就不可以。
强推全缺省构造函数和半缺省构造:
class Date { public: Date(int year=1999 , int month=2 , int day=2 ) { _year = year; _month = month; _day = day; } void Print() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; // Date f(); 函数声明 int main() { Date d1(2003,2,3); d1.Print(); Date d2(2003, 2); d2.Print(); return 0; }
终端显示:
这样好处还是很多,如果需要多次使用构造函数,就不需要每次都传参,传常需要使用的便可,增加代码的可读性,提高效率。
四:拷贝构造函数
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
一:拷贝构造函数的特性
1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。所以我们必须使用引用。
拷贝构造函数原型:
类名 (const 类型 & 形参)
直接存放类里面public域中。
繁琐 其实就是在帮你拷贝一个相同的供呢使用,不多说了,上代码:
class Date { public: Date(int year , int month , int day) { _year = year; _month = month; _day = day; } /*Date d2(d1);*///拷贝构造函数 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; }; int main() { Date d1(2003,2,3); Date d2(d1); d1.Print(); d2.Print(); return 0; }
终端显示:
非常好我们完美的拷贝下来了,
注意:前面提到我们必须使用引用进行传参,实参传递有指针传参,传值,为什么偏偏使用引用呢?
在调用拷贝构造函数 ,先传参,(如果传值传参),又形成新的拷贝构造,形成无穷递归,我们了解引用的话,引用就跟好的实现,又不浪费内存,也不需要新的变量,在原基础上进行操作,然后我们在使用const便跟好的利用引用。
二:默认实参拷贝函数
若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按
字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
class Date { public: Date(int year , int month , int day) { _year = year; _month = month; _day = day; } /*Date d2(d1);*///拷贝构造函数 //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; }; int main() { Date d1(2003,2,3); Date d2(d1); d1.Print(); d2.Print(); return 0; }
让我们看看终端:
so 酷,这就是默认拷贝了,我没有调用拷贝函数,说明c++功能是真的多呀,基本都会个出默认值,我感觉就好像不能使其他变量成为野的一样。
注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
五:总结
构造函数 :
对于构造函数,我建议如果需要使用初始化,就去使用全缺省或者半缺省,
虽然构造函数是成员函数,编译器会自动帮助我们生成默认构造函数,但是我们还是自己去初始化,虽然方便 但至少逻辑清晰,不会因为初始化的问题乱了方向。
拷贝构造函数:
如果使用拷贝构造函数,调用的时候一定要用引用!!!!!不然会无穷递归,死循环,
也会默认拷贝,但不建议,
由于水平有限,本片博客如果有错误或者不足之处,希望读者纠正,感谢阅读。