当前位置: 首页 > news >正文

C++之类和对象:构造函数,析构函数,拷贝构造,赋值运算符重载

前提:如果一个类是空类,C++中空类中真的什么都没有吗,不是的,编译器会自动生成6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

默认成员函数:构造函数,析构函数,拷贝构造函数,赋值运算符重载,取地址重载,const取地址重载。

构造函数(完成初始化):

我们在设计类的时候,在C语言中必须有一个初始化函数才好定义变量。在C++中类如果我们没有写这个初始化函数,那么编译器就会默认生成一个默认构造函数。这个默认构造函数对内置类型不处理,自定义类型调用它的默认构造函数。

构造函数的调用:

class Data
{
public:Data(int year,int month,int day){_year = year;_month = month;_day = day;}
private://内置类型int _year = 2025;int _month = 4;int _day = 28;//自定义类型//Time _t;
};int main()
{Data day(2025,4,28);//调用带参的构造函数return 0;
}

如果是无参的构造函数:Data day;  即可,不要括号。 

构造函数的特性:

1.函数名与类名相同

2.无返回值

3.对象(也可以称为自定义类型变量)实例化时编译器自动调用对应的构造函数。

4.构造函数也可以重载。

5.如果类中没有显式定义构造函数,编译器才会生成,一旦显式定义就不会生成

6.编译器生成的默认构造函数对内置类型不处理,自定义类型调用它的默认构造函数

7.无参的构造函数,全缺省的构造函数,编译器自动生成的构造函数都是默认构造函数。

注意提醒:编译器生成的默认构造函数对于自定义类型会自动调用它的默认构造函数,而如果我们自己写了一个无参的构造函数就按照自己写的内容来,不会自动调用。

还有一个容易混淆的点:编译器自动生成的默认构造函数会自动调用自定义类型的默认构造函数,如果这个自定义类型的构造函数如果不是默认构造函数就会报错。

//会报错的代码:
class Time
{
public://不是默认构造函数Time(int hour,int minute,int second){cout << "Time" << endl;_hour = hour;_minute = minute;_second = second;}
private:int _hour;int _minute;int _second;
};class Data
{
private://内置类型int _year;int _month;int _day;//自定义类型Time _t;
};int main()
{Data day;return 0;
}

上述代码 Data 类中就有 Time 自定义类型,但是构造函数不是默认构造函数所以报错了。

//正确的代码:
class Time
{
public://全缺省函数Time(int hour=0,int minute=0,int second=0){cout << "Time" << endl;_hour = hour;_minute = minute;_second = second;}
private:int _hour;int _minute;int _second;
};class Data
{
private://内置类型int _year;int _month;int _day;//自定义类型Time _t;
};int main()
{Data day;return 0;
}

所以我们尽量使用全缺省构造函数。

还有对于编译器自动生成的默认构造函数,针对内置类型不做处理,C++11有了内置类型成员在类中声明时可以给默认值 就是在声明时给缺省值:

析构函数(完成清理工作):

析构函数是在对象销毁时完成对象中资源的清理工作,对象在销毁时会自动调用析构函数。

析构函数不是销毁对象本身,对象本身是由编译器销毁的。

析构函数的特性:

1.析构函数名是类名前面加字符~。

2.无参数也无返回值。

3.一个类只有一个析构函数,如果没有显式定义,编译器会自动生成默认的析构函数,注意:析构函数不能重载。

4.对象生命周期结束时,系统会自动调用析构函数

5.编译器生成的默认析构函数,对内置类型不做处理,对自定义类型调用它的析构函数。

6.如果类中有申请资源,例如:动态申请空间之类的需要手动销毁,必须要写析构函数手动销毁,否则会造成资源泄漏。如果没有资源申请则可以默认析构函数。

#include<iostream>
using namespace std;class Time
{
public:Time(int hour=0,int minute=0,int second=0){cout << "Time" << endl;_hour = hour;_minute = minute;_second = second;}~Time(){cout << "Time析构函数" << endl;}
private:int _hour;int _minute;int _second;
};class Data
{
public:Data(int year,int month,int day){cout << "Data" << endl;_year = year;_month = month;_day = day;}~Data(){cout << "Data析构函数" << endl;}
private:int _year = 2025;int _month = 4;int _day = 28;
};int main()
{Data day(2025,4,28);Time TY;return 0;
}

 上述代码让我们明白系统调用析构函数的顺序:局部对象(后定义先析构)-> 局部静态对象 ->

全局对象(后定义先析构):

拷贝构造函数(同类对象初始化创建对象):

拷贝构造函数:只有单个形参,形参是本类类型对象的引用(一般用const修饰)用已存在的自定义类型对象创建新对象时由编译器自动调用。

拷贝构造的特性:

1.拷贝构造函数是构造函数的一个重载形式。

2.拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器会报错,会引发无尽递归调用。

3.如果类中没有显式定义拷贝构造,编译器会生成默认拷贝构造函数,默认拷贝构造对内置类型按内存存储按字节序完成拷贝,是值拷贝,或者叫浅拷贝。自定义类型调用它的拷贝构造。

4.编译器的默认拷贝构造,只会完成浅拷贝,一旦类中有资源申请,拷贝构造函数必须要写,例如:有动态内存管理,那么指向动态内存的指针,浅拷贝只会拷贝地址,不会生成相同的动态内存,会导致很多问题。

5.拷贝构造典型调用场景:使用已存在对象创建新对象 / 函数参数类型为类类型对象 / 函数返回值类型为类类型对象。

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}~Data(){cout << "Data析构函数" << endl;}
private://内置类型int _year;int _month;int _day;
};int main()
{Data day1;Data day2(day1);return 0;
}

 

当函数传值传参时或者返回值时调用拷贝构造:

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}~Data(){cout << "Data析构函数" << endl;}
private://内置类型int _year;int _month;int _day;
};Data Test(Data d)
{Data tmp(d);return tmp;
}int main()
{Data day1;Test(day1);return 0;
}

 

实际过程中编译器为了效率会减少一些拷贝构造优化拷贝构造。为了提高效率,一般对象传参尽量使用引用类型,返回值看情况。

赋值运算符重载(把一个对象赋值给另一个对象):

运算符重载:

C++引入了运算符重载,运算符重载是具有特殊函数名的函数。

注意:1.不能通过连接其他符号来创建新操作符:operator@

2.重载操作符必须有一个类类型参数,不能去重载运算符改变内置类型的行为。

3.  .*   ::   sizeof  ?:  .   以上五个运算符不能被重载。

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}//这里左操作数是this指针,指向调用函数的对象bool operator==(const Data& d2){return _year == d2._year && _month == d2._month && _day == d2._day;}~Data(){cout << "Data析构函数" << endl;}
private://内置类型int _year;int _month;int _day;
};int main()
{Data day1;Data day2(day1);cout << (day1 == day2) << endl;return 0;
}

 赋值运算符重载:

1.赋值运算符重载格式:1参数类型 const T& ,传递引用提高效率。2返回值类型 T& 支持连续赋值且提高效率。3检查是否给自己赋值。4返回 *this,要符合连续赋值的含义。

2.赋值运算符只能重载成类的成员函数不能重载成全局函数。因为类中没有显式实现,编译器会生成默认赋值运算符重载,如果在全局中也有一个,就冲突了。

3.编译器生成的默认运算符重载,对内置类型浅拷贝,对自定义类型调用它的赋值运算符重载。

还是需要注意类中是否有资源申请,有的话必须要实现。

class Data
{
public:Data(int year = 2025,int month = 4,int day = 29){cout << "Data" << endl;_year = year;_month = month;_day = day;}Data(const Data& d){cout << "Data拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}Data& operator= (const Data& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}bool operator== (const Data& d2){return _year == d2._year && _month == d2._month && _day == d2._day;}~Data(){cout << "Data析构函数" << endl;}
private://内置类型int _year;int _month;int _day;
};int main()
{Data day1(1,2,3);Data day2;day2 = day1;return 0;
}

和拷贝构造的区别:拷贝构造是一个存在的对象创建一个新对象并且赋值,赋值运算符重载是两个存在的对象,一个给另一个赋值。

相关文章:

  • 从Transformer原理角度来看,prompt设置输出字数限制会生效的原因
  • 8.idea创建maven项目(使用Log4j日志记录框架+Log4j 介绍)
  • Java后端程序员学习前端之html
  • 关于浏览器对于HTML实体编码,urlencode,Unicode解析
  • gem5-gpu 安装过程碰到的问题记录 关于使用 Ruby + Garnet
  • RabbitMQ 启动报错 “crypto.app“ 的解决方法
  • 余额分账和代付有什么区别?
  • AVL树左旋右旋的实现
  • Error: error:0308010C:digital envelope routines::unsupported 高版本node启动低版本项目运行报错
  • Android启动应用时屏蔽RecyclerView滑动,延时后再允许滑动,Kotlin
  • 【免费下载】1985-2023年全国土地利用数据
  • GD32F407单片机开发入门(十七)内部RTC实时时钟及实战含源码
  • 请简述一下什么是 Kotlin?它有哪些特性?
  • React Native 太慢:kotlin-gradle-plugin-2.0.21-gradle76.jar 下载太慢
  • git学习之git常用命令
  • MATLAB函数调用全解析:从入门到精通
  • 【最新 MCP 战神手册 08】工具使用详解:实现 AI 行动
  • Spring MVC 进阶 - 拦截器、异常处理、数据校验
  • 【东枫电子】AI-RAN:利用人工智能驱动的计算基础设施变革 RAN
  • [逆向工程]如何理解小端序?逆向工程中的字节序陷阱与实战解析
  • 五一去哪儿| 追着花期去旅行,“赏花经济”绽放文旅新活力
  • 神舟十九号载人飞船因东风着陆场气象原因推迟返回
  • 习近平访问金砖国家新开发银行
  • 外交部:美方应在平等、尊重和互惠的基础上同中方开展对话
  • 民生访谈|规范放生活动、提升供水品质……上海将有这些举措
  • 外交部:印度香客赴中国西藏神山圣湖朝圣将于今年夏季恢复