热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++类中的三大函数(构造,析构,拷贝)

下面一段话与大家共勉:每个人的一生都会遇到很多边界,有些边界可以突破,有些则不能。那些无法突破的边界就是你的极限,而划分边界的标准就是“阈值”。

下面一段话与大家共勉:

每个人的一生都会遇到很多边界,有些边界可以突破,有些则不能。那些无法突破的边界就是你的极限,而划分边界的标准就是“阈值”。每次突破阈值之后,人生轨迹就会发生剧烈变化,其间需要你做出很多思考和判断,直到最后找到自己的极限。

时间过的很快,转眼间,已经半个多月没更新了,这段时间很忙,事情非常多,最近沉迷于高数,下个决定,大二参加数竞,所以以后可能不会那么频繁的更新,可能会把更多时间放在数学上面。今天和大家分享一下C++中在创建类的时候编译器会提供给一个类至少三个函数,分别是默认构造函数,析构函数,拷贝构造函数。

目录:

一.构造函数

1.构造函数的作用

2.构造函数的语法 类名(){}

一.构造函数

1.构造函数的作用

我们在创建好类的对象之后,首先对它的每一个成员属性赋值之后再对它们进行输出操作,如果不赋值就输出,这些值就会是垃圾值。而为了代码的简介,一次性为所有成员属性初始化,C++的类提供了这样的一个函数—构造函数。

2.构造函数的语法 类名(){}

1)构造函数,没有返回值也不写void

2) 函数名称与类名相同

3)构造函数可以有参数,因此可以发生重载

4)程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

二.析构函数

1.析构函数的作用

析构函数的作用与构造函数相反,一般是执行对象的清理工作,当对象的生命周期结束的时候,会自动的调用。析构函数的作用并不是删除对象,在对象撤销它所占用的内存之前,做一些清理的工作。清理之后,这部分内存就可以被系统回收再利用了。在设计这个类的时候,系统也会默认的提供一个析构函数。在对象的生命周期结束的时候,程序就会自动执行析构函数来完成这些工作。同构造函数,用户自己定义,系统自动调用。

2.析构函数的语法~类名(){}

1)析构函数,没有返回值也不写void

2) 函数名称与类名相同,在名称前加上符号 ~

3)析构函数不可以有参数,因此不可以发生重载

4) 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次

代码演示:

class Person
{public://构造函数Person(){cout <<"Person的构造函数调用" <//析构函数
~Person(){cout <<"Person的析构函数调用" <};
void test01()
{Person p;
}
int main(){test01();system("pause");return 0;}

三.构造函数的分类及调用

1.两种分类方式&#xff1a;

按参数分为&#xff1a; 有参构造和无参构造

按类型分为&#xff1a; 普通构造和拷贝构造

2.三种调用方式&#xff1a;

括号法

显示法

隐式转换法

//1、构造函数分类
// 按照参数分类分为 有参和无参构造 无参又称为默认构造函数
// 按照类型分类分为 普通构造和拷贝构造
class Person {
public://无参&#xff08;默认&#xff09;构造函数
Person() {
cout <<"无参构造函数!" <}//有参构造函数
Person(int a) {
age &#61; a;
cout <<"有参构造函数!" <}//拷贝构造函数
Person(const Person& p) {
age &#61; p.age;
cout <<"拷贝构造函数!" <}//析构函数
~Person() {
cout <<"析构函数!" <}public:
int age;
};//2、构造函数的调用
//调用无参构造函数
void test01() {
Person p; //调用无参构造函数
}//调用有参的构造函数
void test02() {
//2.1 括号法&#xff0c;常用
Person p1(10);
//注意1&#xff1a;调用无参构造函数不能加括号&#xff0c;如果加了编译器认为这是一个函数声明
//Person p2();//2.2 显式法
Person p2 &#61; Person(10);
Person p3 &#61; Person(p2);
//Person(10)单独写就是匿名对象 当前行结束之后&#xff0c;马上析构//2.3 隐式转换法
Person p4 &#61; 10; // Person p4 &#61; Person(10);
Person p5 &#61; p4; // Person p5 &#61; Person(p4);
//注意2&#xff1a;不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
//Person p5(p4);
}
int main() {
test01();
//test02();
system("pause");
return 0;
}

四.拷贝构造函数调用时机

C&#43;&#43;中拷贝构造函数调用时机通常有三种情况

1.使用一个已经创建完毕的对象来初始化一个新对象

2.值传递的方式给函数参数传值

3.以值方式返回局部对象

class Person {
public:
Person() {
cout <<"无参构造函数!" <mAge &#61; 0;
}
Person(int age) {
cout <<"有参构造函数!" <mAge &#61; age;
}
Person(const Person& p) {
cout <<"拷贝构造函数!" <mAge &#61; p.mAge;
}
//析构函数在释放内存之前调用
~Person() {
cout <<"析构函数!" <}
public:
int mAge;
};
//1. 使用一个已经创建完毕的对象来初始化一个新对象
void test01() {
Person man(100); //p对象已经创建完毕
Person newman(man); //调用拷贝构造函数
Person newman2 &#61; man; //拷贝构造
//Person newman3;
//newman3 &#61; man; //不是调用拷贝构造函数&#xff0c;赋值操作
}
//2. 值传递的方式给函数参数传值
//相当于Person p1 &#61; p;
void doWork(Person p1) {}
void test02() {
Person p; //无参构造函数
doWork(p);
}
//3. 以值方式返回局部对象
Person doWork2()
{
Person p1;
cout <<(int *)&p1 <return p1;
}
void test03()
{
Person p &#61; doWork2();
cout <<(int *)&p <}
int main() {
//test01();
//test02();
test03();
system("pause");
return 0;
}

五.构造函数调用规则

默认情况下&#xff0c;c&#43;&#43;编译器至少给一个类添加3个函数

1&#xff0e;默认构造函数(无参&#xff0c;函数体为空)

2&#xff0e;默认析构函数(无参&#xff0c;函数体为空)

3&#xff0e;默认拷贝构造函数&#xff0c;对属性进行值拷贝

构造函数调用规则如下&#xff1a;

如果用户定义有参构造函数&#xff0c;c&#43;&#43;不在提供默认无参构造&#xff0c;但是会提供默认拷贝构造

如果用户定义拷贝构造函数&#xff0c;c&#43;&#43;不会再提供其他构造函数

class Person {
public:
//无参&#xff08;默认&#xff09;构造函数
Person() {
cout <<"无参构造函数!" <}
//有参构造函数
Person(int a) {
age &#61; a;
cout <<"有参构造函数!" <}
//拷贝构造函数
Person(const Person& p) {
age &#61; p.age;
cout <<"拷贝构造函数!" <}
//析构函数
~Person() {
cout <<"析构函数!" <}
public:
int age;
};
void test01()
{
Person p1(18);
//如果不写拷贝构造&#xff0c;编译器会自动添加拷贝构造&#xff0c;并且做浅拷贝操作
Person p2(p1);
cout <<"p2的年龄为&#xff1a; " <}
void test02()
{
//如果用户提供有参构造&#xff0c;编译器不会提供默认构造&#xff0c;会提供拷贝构造
Person p1; //此时如果用户自己没有提供默认构造&#xff0c;会出错
Person p2(10); //用户提供的有参
Person p3(p2); //此时如果用户没有提供拷贝构造&#xff0c;编译器会提供
//如果用户提供拷贝构造&#xff0c;编译器不会提供其他构造函数
Person p4; //此时如果用户自己没有提供默认构造&#xff0c;会出错
Person p5(10); //此时如果用户自己没有提供有参&#xff0c;会出错
Person p6(p5); //用户自己提供拷贝构造
}
int main() {
test01();
system("pause");
return 0;
}

六.深拷贝与浅拷贝

浅拷贝&#xff1a;简单的赋值拷贝操作

深拷贝&#xff1a;在堆区重新申请空间&#xff0c;进行拷贝操作

示例&#xff1a;

class Person {
public:
//无参&#xff08;默认&#xff09;构造函数
Person() {
cout <<"无参构造函数!" <}
//有参构造函数
Person(int age ,int height) {
cout <<"有参构造函数!" <m_age &#61; age;
m_height &#61; new int(height);
cout <<"拷贝构造函数!" <//如果不利用深拷贝在堆区创建新内存&#xff0c;会导致浅拷贝带来的重复释放堆区问题
m_age &#61; p.m_age;
m_height &#61; new int(*p.m_height)
}
//拷贝构造函数
Person(const Person& p) {
;
}
//析构函数
~Person() {
cout <<"析构函数!" <if (m_height !&#61; NULL)
{
delete m_height;
}
}
public:
int m_age;
int* m_height;
};
void test01()
{
Person p1(18, 180);
Person p2(p1);
cout <<"p1的年龄&#xff1a; " <cout <<"p2的年龄&#xff1a; " <}
int main() {
test01();
system("pause");
return 0;
}

总结&#xff1a;如果属性有在堆区开辟的&#xff0c;一定要自己提供拷贝构造函数&#xff0c;防止浅拷贝带来的问题


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了在多平台下进行条件编译的必要性,以及具体的实现方法。通过示例代码展示了如何使用条件编译来实现不同平台的功能。最后总结了只要接口相同,不同平台下的编译运行结果也会相同。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
author-avatar
爱飞扬无限_316
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有