构造函数以及析构函数

  • 对象初始化和清理
  • 构造函数以及析构函数
  • 构造函数的分类
    • 括号法
    • 显示法
    • 隐式转换法
    • 匿名对象
  • 拷贝构造函数的调用时机
  • 构造函数的调用规则
  • 深拷贝和浅拷贝
  • 初始化列表
  • 类对象作为类成员
  • 静态成员

对象初始化和清理

C++面向对象来源于生活,每个对象都会有初始化设置以及对象销毁前的清理数据的设置

构造函数以及析构函数

对象的初始化和清理是非常重要的安全问题

  • 一个对象或者变量没有初始化状态,对其使用后果也是未知
  • 使用完一个对象或者变量,没有及时清理,也会造成一定的安全问题

构造函数主要用于创造对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
析构函数主要用于销毁前系统自动调用,执行一些清理工作

构造函数语法:类名()

  • 构造函数 没有返回值 也不写void
  • 函数名称和类名相同
  • 构造函数可以有参数,因此可以发生重载
  • 程序在调用对象时自动调用构造函数,无需手动调用,且只会调用一次

析构函数语法:~类名()

  • 析构函数,没有返回值也不写void
  • 函数名称是在类名前加~
  • 析构函数不可以有参数 因此不能发生重载
  • 程序在对象销毁时自动调用析构函数,无需手动调用,且只会调用一次
#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:student();~student();
};
student::student(){cout << "构造函数" << endl;
}
student::~student() {cout << "析构函数" << endl;
}
int main()
{   student stu;system("pause");return 0;
}

构造函数的分类

两种分类方式:

  • 按参数:有参构造和无参构造
  • 按类型:普通构造和拷贝构造

三种调用方式:

  • 括号法
  • 显示法
  • 隐式转换法

调用默认构造的时候不要写括号()系统会默认成是函数的
不要利用拷贝构造函数初始化匿名对象 编译器会认为 类名(p3) ==person p3

括号法

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:student();//无参构造student(int age);//有参构造student(const student&b);//拷贝构造~student();
};
student::student()
{cout << "无参构造" << endl;
}
student::student(int age)
{cout << "有参构造" << endl;
}
student::student(const student&b)
{cout << "拷贝构造" << endl;
}
student::~student()
{cout << "析构函数" << endl;
}int main()
{   /*括号法*/student stu1;student stu2(18);student stu3(stu2);system("pause");return 0;
}

显示法

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:student();//无参构造student(int age);//有参构造student(const student&b);//拷贝构造~student();
};
student::student()
{cout << "无参构造" << endl;
}
student::student(int age)
{cout << "有参构造" << endl;
}
student::student(const student&b)
{cout << "拷贝构造" << endl;
}
student::~student()
{cout << "析构函数" << endl;
}int main()
{   /*显示法*/student stu1;student stu2 = student(18);student stu3 = student(stu2);system("pause");return 0;
}

隐式转换法

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:student();//无参构造student(int age);//有参构造student(const student&b);//拷贝构造~student();
};
student::student()
{cout << "无参构造" << endl;
}
student::student(int age)
{cout << "有参构造" << endl;
}
student::student(const student&b)
{cout << "拷贝构造" << endl;
}
student::~student()
{cout << "析构函数" << endl;
}int main()
{   /*隐式转换法*/student stu1;student stu2 = 10;student stu3 = stu2;system("pause");return 0;
}

匿名对象

匿名对象的意思就是当执行结束后系统立马收回

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:student();//无参构造student(int age);//有参构造student(const student&b);//拷贝构造~student();
};
student::student()
{cout << "无参构造" << endl;
}
student::student(int age)
{cout << "有参构造" << endl;
}
student::student(const student&b)
{cout << "拷贝构造" << endl;
}
student::~student()
{cout << "析构函数" << endl;
}int main()
{   /*匿名对象*/student(1);system("pause");return 0;
}

拷贝构造函数的调用时机

调用时机

  • 使用一个已经穿件完毕的对象来初始化一个新的对象
  • 以值传递的方式给函数参数传值
  • 以值方式返回局部对象
#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:student();//无参构造student(int age);//有参构造student(const student&b);//拷贝构造~student();
};
student::student()
{cout << "无参构造" << endl;
}
student::student(int age)
{cout << "有参构造" << endl;
}
student::student(const student&b)
{cout << "拷贝构造" << endl;
}
student::~student()
{cout << "析构函数" << endl;
}void test1(student stu)
{}
student test2()
{student stu;cout << &stu << endl;return stu;
}
int main()
{   /*使用一个已经创建完毕的对象来初始化一个新对象*/student stu(18);student stu1(stu);/*以值传递的方式给函数传递值*/test1(stu);/*以值的方式返回局部对象*/student stu2 = test2();cout << &stu2 << endl;system("pause");return 0;
}


上面的代码输出的地址也表示了 拷贝构造函数是拷贝一个新的构造函数,所以地址会不同

构造函数的调用规则

默认情况下,c++编译器至少给1个类添加3个函数

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数,对属性进行值拷贝

构造函数调用规则:

  • 如果用户定义有参构造函数,c++不提供默认无参构造函数,但依然会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

下面几张截图就可以充分说明上述构造函数调用规则:
1. 只定义有参构造,声明无参构造会报错 声明拷贝构造不会报错

2. 只定义拷贝构造,声明无参构造和有参构造都会报错

3. 定义了无参构造和有参构造,声明拷贝构造不会报错

深拷贝和浅拷贝

浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作

先把代码放上来,然后说一下区别

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:int age;int *hight;student();//无参构造student(int xage,int xhight);//有参构造student(const student&b);//拷贝构造~student();
};
student::student()
{cout << "无参构造" << endl;
}
student::student(int xage, int xhight)
{age = xage;hight = new int(xhight);cout << "有参构造" << endl;
}
student::student(const student&b)
{cout << "拷贝构造" << endl;age = b.age;hight = b.hight;//浅拷贝hight = new int(*b.hight);//深拷贝
}
student::~student()
{if (hight != NULL){delete hight;hight = NULL;}cout << "析构函数" << endl;
}int main()
{   student stu(18, 180);cout << stu.age << endl;cout << stu.hight << endl;student stu1(stu);cout << stu1.age << endl;cout << stu1.hight << endl;system("pause");return 0;
}

上面代码不可直接使用,在深拷贝和浅拷贝哪里应该要注释一个,现在我来贴出不同情况下运行后的结果
浅拷贝

深拷贝

首先肯定的是,这个代码在浅拷贝的时候运行出错了。首先我们可以看到,拷贝之后的heigh的地址指向的是一样。那么在程序结束的时候,析构函数会delete这个指针,但是由于浅拷贝中hight中2个函数指向的地址一样,所以析构函数相当于delete一个相同的指针2次,那么必然会出错的。
深拷贝是自己在堆区重新开辟的一个新的空间,自然而然2个hight指向的地址不是一个,这个我们打印的结果也看到了,所以在析构函数释放的时候自然不会报错

初始化列表

前面我们写的代码中有参构造,都是在函数内部实现属性和形参的赋值
这个初始化列表作用就是C++提供了初始化列表语法,用来初始化属性
语法:槽函数():属性1(值1)属性2(值2)

传统方式

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:int a, b, c;student(int xa,int xb,int xc);//有参构造//student(int xa, int xb, int xc) :a(xa), b(xb), c(xc)//{}~student();
};student::student(int xa, int xb, int xc)
{a = xa;b = xb;c = xc;cout << "有参构造" << endl;
}student::~student()
{cout << "析构函数" << endl;
}int main()
{   student stu(1, 2, 3);cout << stu.a << endl;cout << stu.b << endl;cout << stu.c << endl;system("pause");return 0;
}

初始化列表

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:int a, b, c;//student(int xa,int xb,int xc);//有参构造student(int xa, int xb, int xc) :a(xa), b(xb), c(xc){}~student();
};//student::student(int xa, int xb, int xc)
//{//  a = xa;
//  b = xb;
//  c = xc;
//  cout << "有参构造" << endl;
//}student::~student()
{cout << "析构函数" << endl;
}int main()
{   student stu(1, 2, 3);cout << stu.a << endl;cout << stu.b << endl;cout << stu.c << endl;system("pause");return 0;
}

类对象作为类成员

C++中类的成员可以是另外一个类,我们称改成员为对象成员
当其他类对象作为本类成员,构造时候要先构造对象,在构造自身
析构函数刚好相反

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class phone
{public:string phonename;phone(string a){phonename = a;cout << "phone 的构造函数" << endl;}~phone(){cout << "phone 的析构函数" << endl;}
};
class student
{public:string name;phone phones;student(string xname, string xphone):name(xname),phones(xphone){cout << "student 的构造函数" << endl;}~student(){cout << "student 的析构函数" << endl;}
};int main()
{   student stu("张三","华为");system("pause");return 0;
}

静态成员

静态成员就是在成员变量和成员函数前加关键字static

静态成员变量

  • 所有对象共享一份数据
  • 在编译阶段分配内存
#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:static int age;
};
int student::age = 18;int main()
{   student stu1;cout << stu1.age << endl;student stu2;stu2.age = 20;cout << stu1.age << endl;cout << &stu1.age << endl;cout << &stu2.age << endl;system("pause");return 0;
}

访问方式:

  1. 通过对象访问
  2. 通过类名访问
  3. 静态成员访问权限私有情况下也访问不到

类内声明,类外初始化

  • 静态成员函数
  • 所有对象共用一个函数
  • 静态成员函数只能访问静态成员变量
  • 静态成员函数权限是私有的也无法访问到

#include <iostream>
#include <ctime>
#include <string>//c++中字符串需要添加这个头文件
#include <fstream>
using namespace std;class student
{public:static int age;static void fun1(){age = 200;}
private:static void fun2(){}
};
int student::age = 18;int main()
{   student stu1;cout << stu1.age << endl;student::fun1();cout << stu1.age << endl;system("pause");return 0;
}

C++:构造函数以及析构函数相关推荐

  1. C++ 笔记(17)— 类和对象(构造函数、析构函数、拷贝构造函数)

    1. 构造函数 构造函数是一种特殊的函数(方法),在根据类创建对象时被调用.构造函数是一种随着对象创建而自动被调用的函数,它的主要用途是为对象作初始化. 构造函数的名称与类的名称是完全相同的,并且不会 ...

  2. php构造和析构方法,php5构造函数与析构函数实例

    自php5起,有了构造函数与析构函数. 这使得php更富有面向对象的魅力了. 在php4时,构造函数用的是与类同名的函数来进行构造这个动作. 例如: 复制代码 代码示例: /* * myclass.p ...

  3. 提高C++性能的编程技术笔记:构造函数和析构函数+测试代码

    对象的创建和销毁往往会造成性能的损失.在继承层次中,对象的创建将引起其先辈的创建.对象的销毁也是如此.其次,对象相关的开销与对象本身的派生链的长度和复杂性相关.所创建的对象(以及其后销毁的对象)的数量 ...

  4. c++, 派生类的构造函数和析构函数 , [ 以及operator=不能被继承 or Not的探讨]

    说明:文章中关于operator=实现的示例,从语法上是对的,但逻辑和习惯上都是错误的. 参见另一篇专门探究operator=的文章:<c++,operator=>http://www.c ...

  5. C++中的构造函数VS析构函数

    1.构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行.构造函数的名称与类的名称的完全相同的,并且不会返回任何数据类型,也不会返回void.构造函数用于为某些成员变量设置初 ...

  6. 多继承的构造函数和析构函数

    //程序2:多继承的构造函数 与 析构函数 #include<iostream> using namespace std;class A { public: A() { cout<& ...

  7. c++ 构造函数析构函数 数据安全_C++知识点 16:构造函数和析构函数的语法

    #define _CRT_SECURE_NO_WARNINGS #include using namespace std;// 创建一个类( 类内包括: 2个构造函数,一个析构函数) class Pe ...

  8. 多重继承的构造函数和析构函数

    多重继承的构造函数和析构函数的执行顺序: //此处不做注释和说明了,看程序能读懂的 #include <iostream> using namespace std; class base1 ...

  9. C++中构造函数和析构函数

    [注]致力于将知识讲明白!不懂请留言! 构造函数 定义 它是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中. 另外,一个类可以有 ...

  10. c++ map 析构函数_C++学习刷题6--C++类的使用:构造函数、析构函数和类的使用

    一.前言 本部分为C++语言刷题系列中的第4节,主要讲解这几个知识点:构造函数.析构函数和类的使用.欢迎大家提出意见.指出错误或提供更好的题目! 二.知识点讲解 由以前知识可知,类的实现中包含成员变量 ...

最新文章

  1. mysql 用命令行复制表数据到新表
  2. 消费消息删除_【进阶之路】可靠消息最终一致性解决方案
  3. 第4章 Python 数字图像处理(DIP) - 频率域滤波7 - 二维DFT和IDFT的一些性质 - 傅里叶频谱和相角
  4. java与php链条遇到的坑,记一次Java加密加签算法到php的坑
  5. JS:ES6-2 const 关键字
  6. idea 2019最新版无法打开报错问题,Error occurred during initialization of VM Initial heap size set to a larger va
  7. SAS9.4安装简易教程(保姆级)附带报错处理
  8. ctfmon是什么启动项_Win7启动项找不到ctfmon进程无法正常使用输入法的解决方法...
  9. 双系统如何卸载linux
  10. 值得收藏-50个免费可商用图库
  11. 诗词大全给力版_小学生诗词必背75+80首,课内课外全掌握,还送配套练习册amp;视频课...
  12. 华为OD(外包)社招技术二面,总结复盘
  13. 无插件播放之http-flv
  14. python显示gif图片报错_4种方法(plglet、tkinter、guizero、pygame)的GUI中显示gif
  15. Unity中的特殊的文件夹
  16. 云之讯张雯:云计算时代融合通讯开发及算法优化
  17. 记录12款MacBook Pro MC946,A1398拆主板换新喇叭的过程
  18. 机器学习算法工程师面试学习经验
  19. 记一次godaddy上同一共享主机上部署多站
  20. Android onMeasure、Measure、measureChild、measureChildren 一些简要说明

热门文章

  1. CloudFlare域名管理系统
  2. Flutter实现微信支付和iOS IAP支付,ndk开发入门
  3. liquidFill---实现柱状水滴图
  4. 详细分析stm32f10x.h
  5. Win11游戏模式怎么开启?Win11开启游戏模式的方法
  6. 推荐系统 - 基于标签的推荐算法
  7. win11锁屏壁纸不更新,且全黑的解决办法
  8. 【音视频】常见问题整理 - 技术提升1.0
  9. fbi测试_FBI的完整形式是什么?
  10. 【Typora】实用使用技巧