C++类中的6个默认函数之构造函数、析构函数、拷贝构造函
数、赋值运算符重载函数
类中6个默认函数,如果在定义类时没有定义这6个函数的某⼏个,编译器会提供相应的默认函数,
如果定义了这6个函数的某⼏个,编译器则不会提供相应的默认函数,
系统提供的这6个默认函数都是公有的,都是内联的
1. 构造函数
2. 析构函数
3. 拷贝构造函数
4. 赋值运算符重载函数
5. 取地址操作符重载函数
6. const修饰的取地址操作符重载函数
构造函数
1.构造函数与类名相同,并且没有返回值
2.构造函数只能系统调⽤,不能⼿动调⽤构造函数
3.构造函数有this指针
4.构造函数可以重载
析构函数
1.析构函数的函数名是~+类名(例:class Student{};析构函数:~Student()),并且没有返回值
2.析构函数可以⼿动调⽤,但⼿动调⽤相当于调⽤普通成员函数,并且在对象的⽣命周期结束后系统会隐式调⽤析构函数。
注意:如果类的成员变量中有指针类型的变量,并且析构函数在释放掉对象的资源后没有将指针置为NULL,⼿动调⽤析构函数运⾏时会崩溃 。
例:
1class Node{
2public:
3 Node(char *str=NULL)
4 {
5  this->str=new char[strlen(str)+1]();
6  strcpy(this->str,str);
7 }
8 ~Node()
9 {
10  delete [] this->str;
11 }
12
13private:
14 char *str;
15};
16
17int main()
18{
19 Node N("Hello");
20 N.~Node();
21return 0;
22}
运⾏程序:
因为⼿动调⽤析构函数释放掉对象所占的的资源,当没有将指针置为NULL时,这个指针就成为了野指针,当对象的⽣命周期结束后系统会隐式调⽤析构函数,此时释放野指针指向的内存,程序发⽣崩溃。
上⾯代码在析构函数中释放了对象所占资源后,将this->str=NULL程序就能正常运⾏
所以若要⼿动调⽤析构函数,当类的成员变量中有指针类型的变量,在析构函数中释放掉对象所占的资源后必须将指针置为NULL
3.析构函数有this指针
4.析构函数不能重载
构造函数与析构函数的调⽤顺序:
例:
1#include<iostream>
2
3class Node{
4public:
5 Node(char *str=NULL)
6 {
7  this->str=new char[strlen(str)+1]();
8  strcpy(this->str,str);
9  std::cout<<this->str<<std::endl;
10 }
11 ~Node()
12 {
13  std::cout<<this->str<<std::endl;
14  delete [] this->str;
15  this->str=NULL;
16 }
17
18private:
19 char *str;
20};
21
22int main()
23{
24 Node n1("n1");
25 Node n2("n2");
26 Node n3("n3");
27
28return 0;
29}
运⾏结果:
从上⾯的结果可以看出构造函数是和代码的运⾏顺序相同,析构函数刚好相反
简单来说,先构造的后析构,后构造的先析构
这是由于这些对象都是在栈上开辟内存⽣成的,栈的特点是先进后出
区别:
如果对象是在堆上开辟内存⽣成的,由于堆内存上开辟的空间不会随着函数的结束⽽释放,所以对象的⽣命周期不会结束,系统也不会隐式调⽤析构函数释放对象所占的资源,此时会造成内存泄漏(包括对象所占内存和他所占资源的内存)。
我们必须⼿动释放对象的堆内存,此时对象的⽣命周期结束,系统会隐式调⽤析构函数释放掉对象所占资源,然后再释放掉对象所占的堆内存,保证不会发⽣内存泄露。
此时对象调⽤析构函数的顺序取决于我们释放对象的堆内存顺序。
拷贝构造函数
拷贝构造函数是⽤以存在的对象去⽣成⼀个新对象
系统默认的拷贝构造函数是⼀个浅拷贝,它只将对象在栈上的数据进⾏拷贝,并没有将对象在堆上⾯的数据进⾏拷贝。
如果对象在堆上占有资源,我们必须⼿动实现深拷贝构造函数,将对象在堆上的数据也进⾏拷贝,
如果对象仅仅只在栈上占有资源,我们可以不⼿动实现拷贝构造函数⽽调⽤系统提供的拷贝构造函数
1.拷贝构造函数的函数名与类名相同,没有返回值
strcpy报错2.拷贝构造函数的参数必须为对象的引⽤,为了防⽌在拷贝构造函数中将已存在对象的数据修改,我们通常加上const    例:
1#include<iostream>
2
3class Node{
4public:
5 Node(char *str=NULL)
6 {
7  this->str=new char[strlen(str)+1]();
8  strcpy(this->str,str);
9  std::cout<<this<<"  "<<this->str<<std::endl;
10 }
11 ~Node()
12 {
13  delete [] this->str;
14  this->str=NULL;
15 }
16
17 Node(const Node& rhs)
18 {
19  if( this!=&rhs)
20  {
21  this->str=new char[strlen(rhs.str)+1]();
22  strcpy(this->str,rhs.str);
23  }
24 }
25 void Show()
26 {
27      std::cout<<this<<"  "<<this->str<<std::endl;
28 }
29private:
30 char *str;
31};
32
33int main()
34{
35 Node n1("n1");
36 Node n2("n2");
37 Node n3("n3");
38 Node n(n1);
39 n.Show();
40return 0;
41}
运⾏结果:
那我们能否把拷贝构造函数的参数改为对象传递,⽽不是⼀个对象的引⽤呢?
即将拷贝构造的函数名改为  Node(const Node rhs)
我们修改代码后编译发现程序报错,这是为什么呢?
我们可以看出,当拷贝构造函数的形参改为对象传递时,在调⽤拷贝构造时会⼀直递归构造形参对象⽽导致栈溢出,最终程序崩溃
赋值运算符重载函数
含义:把⼀个已存在对象赋值给相同类型的已存在对象
关键字:operator 函数原型 类名& operator=(const  类名&rhs)
返回值为对象引⽤,形参为const 修饰的对象引⽤
例:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。