c++构造和析构

news/2024/11/20 19:34:48/

在这里插入图片描述

1.构造函数

1.构造函数特性

  1. 构造函数名字和类名相同
  2. 构造函数没有返回值(void有返回值,返回值为空)
  3. 不写构造函数,每一个类中都存在默认的构造函数,默认的构造函数是没有参数的
  4. default显示使用默认的构造函数
  5. delete删掉默认函数
  6. 当我们自己写了构造函数,默认的构造函数就不存在
  7. 构造函数是不需要自己调用,在构造函数对象的时候自己调用
  8. 构造函数决定了对象的长相
  9. 无参构造函数可以构造无参对象
  10. 有参构造函数,对象必须要带有参数
  11. 构造函数允许被重载和缺省
  12. 构造函数一般情况是公有属性
  13. 构造函数一般是用来给数据初始化
  14. 构造函数允许调用另一个构造函数,但是必须采用初始化参数列表的写法:
  • 构造函数的初始化参数列表: 构造函数名(参数1,参数2,…):成员1(参数1),成员2(参数2),…{}

2.综合代码

#include<iostream>
#include<string>
using namespace std;
class MM
{
public://构造函数//MM()=default;          //使用的是默认的构造函数//MM()=delete;MM(){cout<<"无参构造函数"<<endl;}MM(int a){cout<<"具有一个参数的构造函数"<<endl;}
protected:
};class Girl
{
public:Girl()=delete;
protected:
};class Student
{
public:Student(){m_age=15,m_name="k";}Student(string name,int age){//做初始化操作m_name=name;m_age=age;}void printStudent(){cout<<m_name<<"\t"<<m_age<<endl;}
protected:string m_name;int m_age;
};class Test{
public://构造函数特殊写法Test(int a,int b):a(a),b(b){}Test():Test(9,8){}             //无参构造函数调用有参构造函数,构造委托//Test()=default;void print(){cout<<a<<"\t"<<b<<endl;}
protected:int a=0;int b=0;
};struct Data
{int a;int b;int c;Data(int a):a(a){}Data(int a,int b,int c):a(a),b(b),c(c){cout<<"调用三个参数的构造函数"<<endl;}void print(){cout<<a<<"\t"<<b<<"\t"<<c<<endl;}
};
int main()
{MM boy;MM girl(1);//Girl girl;    //默认构造函数已经删除,且自己没写构造函数,所以错误//普通对象Student mm("zhangkai",15);mm.printStudent();//new一个对象,new的过程是先在自由存储区创建一个无名对象,再把地址返回Student* pstu = new Student("zhi",29); pstu->printStudent();//对象数组Student stuarry[3]; //无名对象,需要无参构造函数,否则错误stuarry[1].printStudent();stuarry[2].printStudent();stuarry[0].printStudent();//初始化参数列表Test test(99,88);test.print();Test bb;bb.print();Test xx={88,99};  //这个过程也是调用构造函数过程,{}中数据个数要和构造函数参数一致xx.print();Data oo(3);oo.print();Data data(1,2,3);data.print();
}

2.析构函数

1.析构函数特性

  1. 函数名等于~加上类名
  2. 析构函数没有参数,所以析构函数不能被重载也不能被缺省
  3. 对象死亡(生命周期结束)的最后一个事情是调用析构函数
  4. 析构函数都是公有属性
  5. 什么时候写析构函数?
  • 当类的成员new了内存就需要自己手动写析构函数
  1. 不写析构函数,也会存在一个析构函数,但是不具有释放new的内存的功能

2.综合代码

#include<iostream>
using namespace std;
class MM
{
public:MM(){p=new int;}void freeMM(){delete p;p=nullptr;}~MM(){cout<<"我是析构函数"<<endl;delete p;p=nullptr;}
protected:int* p;
};
int main()
{{MM mm;//mm.freeMM();        //当然也可以自己写函数释放,不过要手动释放MM* p=new MM;delete p;            //立刻马上调用析构函数    }cout<<"..............."<<endl;return 0;
}

3.拷贝构造函数

1.拷贝构造函数特性

  1. 不写拷贝构造函数,存在一个默认拷贝构造函数
  2. 拷贝构造函数名和构造函数一样,算是构造函数特殊形态
  3. 拷贝构造函数唯一的一个参数就是对对象的引用
  • 普通引用
  • const引用
  • 右值引用——>移动拷贝
  1. 当我们通过一个对象产生另一个对象时候就会调用拷贝构造函数

2.综合代码

#include<iostream>
#include<string>
using namespace std;
class MM{
public:MM()=default;MM(MM& object){cout<<"调用拷贝构造函数"<<endl;}
protected:
};class Girl{
public:Girl(string name,int age):name(name),age(age){}Girl():Girl("",0){}Girl(const Girl& object){	//拷贝构造函数就是通过一个对象赋值另一个对象name=object.name;age=object.age;cout<<"调用拷贝构造函数"<<endl;}void print(){cout<<name<<"\t"<<age<<endl;}
protected:string name;int age;
};void printBoy(Girl girl)           //调用拷贝构造函数,Gilr girl=实参
{girl.print();
}void printGirl(Girl& girl)
{girl.print();
}void testGirl()
{Girl mm("小妹",19);Girl girl(mm);          //调用girl.print();Girl beauty=mm;           //调用beauty.print();cout<<"传入普通变量"<<endl;printBoy(girl);                //调用cout<<"传入引用"<<endl;        //不调用拷贝构造函数printGirl(girl);//匿名对象的拷贝构造函数,匿名对象是右值,可以用const或者右值引用//const里不可修改//右值引用里提供了可修改的接口Girl xx=Girl("zhangkai",19);xx.print();
}class Boy{
public:Boy(string name,int age):name(name),age(age){}Boy(Boy&& object){name=object.name;age=object.age;cout<<"右值引用的拷贝构造"<<endl;}Boy(Boy& object){name=object.name;age=object.age;cout<<"普通的拷贝构造"<<endl;}
protected:string name;int age;
};void testBoy(){Boy boy("boy",10);          Boy bb=boy;                   //调用普通对象Boy coolman=Boy("dasd",29);   //右值引用的拷贝构造函数//没有打印结果,IDE做了优化,看不到
}
int main()
{MM mm;MM girl=mm;               //会调用拷贝构造函数MM boy(girl);             //会调用拷贝构造函数//string str="dasd";//string str2(str);//string str3=str2;//string类型赋值实际上是调用拷贝构造函数//调用拷贝构造函数语句一定有类名//不调用拷贝构造函数,这是先创建对象,然后赋值,属于运算符重载MM npc;                    npc=girl; cout<<"............"<<endl;	testGirl();cout<<"............"<<endl;testBoy();return 0;
}

3.深浅拷贝问题

深浅拷贝只在类中存在指针,并且做了内存申请的,才会存在引发析构问题(内存释放问题)

  • 默认的拷贝构造都是浅拷贝
  • 拷贝构造函数中做普通的赋值操作也是浅拷贝
错误代码
#include<iostream>
#include<cstring>
using namespace std;
class MM{
public:MM(const char* str,int num){int length=strlen(str)+1;name=new char[length];strcpy_s(name,length,str);age=num;}~MM(){if(name!=nullptr){delete[] name;name=nullptr;}}
protected:char* name;int age;
};
void testQuestion(){MM mm("zhangzhang",19);MM xx=mm;
}
int main() 
{testQuestion();return 0;
}

原因如下图:
在这里插入图片描述

正确代码
#include<iostream>
#include<cstring>
using namespace std;
class MM {
public:MM(const char* str, int num){int length = strlen(str) + 1;name = new char[length];strcpy_s(name, length, str);age = num;}MM(const MM& object){//深拷贝int length = strlen(object.name) + 1;name = new char[length];strcpy_s(name, length, object.name);age = object.age;}~MM(){if (name != nullptr){delete[] name;name = nullptr;}}
protected:char* name;int age;
};
void testQuestion() {MM mm("zhangzhang", 19);MM xx = mm;
}
int main()
{testQuestion();return 0;
}

解释:

在这里插入图片描述

4.构造和析构的顺序问题

  1. 一般情况构造顺序和析构顺序是相反的(先构造后释放,后构造先释放)
  2. new对象,调用delete直接被释放
  3. static对象,最后释放(生命周期最长)
#include<iostream>
#include<string>
using namespace std;
class MM
{
public:MM(string info="A"):info(info){cout<<info;}~MM(){cout<<info;}
protected:string info;
};
void testOrder()
{MM mm1("B");static MM mm2("C");MM* p=new MM("D");delete p;MM arr[3];
}int main()
{testOrder();return 0;
}

5.c++类的组合

介绍:

  • 一个类包含另一个类的对象为数据成员叫做类的组合。当多种事物是一个事物的一部分,采用组合类来完成描述,c++中组合的使用优先于继承
  • 注意:类不能包含自身对象,否则会形成死循环
  • 组合类的构造函数,必须要采用初始化参数列表的方式调用分支类的构造函数
  • 组合类的构造顺序:先构造分支类,分支类的顺序只和声明顺序有关,和初始化参数列表一点毛线关系
#include<iostream>
#include<string>
using namespace std;class MM
{
public:MM(){cout<<"构造mm"<<endl;}MM(string name):name(name){}void print(){cout<<"MM:"<<name<<endl;}
protected:string name;
};class GG
{
public:GG(){cout<<"构造gg"<<endl;}GG(string name,int age):name(name),age(age){}void print(){cout<<name<<"\t"<<age<<endl;}
protected:string name;int age;
};class Family
{
public:Family(string mmName,string ggName,int age):mm(mmName),gg(ggName,age){}//但是分支类中必须存在无参的构造函数Family(){cout<<"构造组合类"<<endl;}void print(){gg.print();mm.print();}
protected:MM mm;GG gg;
};
int main()
{Family dd("mm","gg",19);dd.print();Family object;object.print();    //先分支再组合,且分支的顺序与声明的顺序一致return 0;
}

6.c++类中类

  • 类中类的访问问题以及类中类先申明后定义的写法
  • 类中类依旧受权限限定
  • 访问必须要类名::剥洋葱的方式访问
#include<iostream>
using namespace std;
class xx {
public:xx(){cout<<"外面的构造函数"<<endl;}
protected:
public://类中类依旧受权限限定,就相当于把一个类丢到另外一个类中,他们两个没有关系class dd{public:dd(){cout<<"类中类构造函数"<<endl;}void print(){cout<<"类中类构造函数"<<endl;}protected:};
};
void testlzl()
{xx::dd bb;bb.print();
}
int main()
{testlzl();return 0;
}

http://www.ppmy.cn/news/8658.html

相关文章

C++类继承

1、简单的基类 从一个类派生出令一个类时&#xff0c;原始类称为基类&#xff0c;继承类称为派生类。 class TableTennisPlayer { private:string firstname;string lastname;bool hasTable;public:TableTennisPlayer(const string &fn "none", const string …

2023.01/1801. 积压订单中的订单总数

1801. 积压订单中的订单总数 题意: 给你一个二维整数数组 orders &#xff0c;其中每个 orders[i] [pricei, amounti, orderTypei] 表示有 amounti 笔类型为 orderTypei 、价格为 pricei 的订单。 订单类型 orderTypei 可以分为两种&#xff1a; 0 表示这是一批采购订单 buy …

Java -- 软件开发整体流程;项目环境dev,test,staging,prod

软件开发整体介绍 作为一名软件开发工程师&#xff0c;我们需要了解在软件开发过程中的开发流程&#xff0c; 以及软件开发过程中涉及到的岗位角色&#xff0c;角色的分工、职责&#xff0c; 并了解软件开发中涉及到的四种软件环境。我们将从 软件开发流程、角色分工、软件环境…

Spring6笔记4

十四、GoF之代理模式 14.1 对代理模式的理解 代理模式中有一个非常重要的特点&#xff1a;对于客户端程序来说&#xff0c;使用代理对象时就像在使用目标对象一样。【在程序中&#xff0c;目标需要被保护时】 业务场景&#xff1a;系统中有A、B、C三个模块&#xff0c;使用这…

Java爬虫 爬取某招聘网站招聘信息

Java爬虫 爬取某招聘网站招聘信息一、系统介绍二、功能展示1.需求爬取的网站内容2.实现流程2.1数据采集2.2页面解析2.3数据存储三、获取源码一、系统介绍 系统主要功能&#xff1a;本项目爬取的XX招聘网站 二、功能展示 1.需求爬取的网站内容 2.实现流程 爬虫可以分为三个模…

新年献词 | 明天会更好

序言 今天是2023年的第一天。新年的第一缕阳光已经撒满神州大地。960万平方公里的土地上&#xff0c;人们神采奕奕&#xff0c;斗志昂扬&#xff0c;对新一年的生活充满着无限期待。 每每这时&#xff0c;我的心中思绪万千&#xff0c;无限感慨。回想这一年&#xff0c;总有许…

回味2022

回味20221.前言2.过去的十二个月3.我期望的20231.前言 2021年写给自己的总结&#xff1a;回味2021 一年又一年飞逝的光阴&#xff0c;我想唯有时间留给人的印象最为深刻吧。春去秋来&#xff0c;四季轮回间都是时光的印记。2022年12月30日&#xff0c;25岁的我依旧在这间写下2…

嵌入式:ARM最小系统设计详解

文章目录一、什么是最小系统最小系统结构框图最小系统例板嵌入式最小系统硬件功能二、时钟和功率管理( 一 ) 时钟管理1、时钟电路结构2、锁相环 PLL( 二 ) 功率管理正常模式空闲模式低速模式掉电模式三、电源电路设计四、复位电路设计五、JTAG电路六、存储器扩展特性存储器映射…