类和对象 中篇

类和对象 中篇

​   在上篇中,我们介绍了类的基础部分,本篇我们讲解C++类的六大默认成员函数

Pasted image 20240708193844

​   所谓默认成员函数,就是我们不写编译器也会自动生成,自动调用的函数。而自动生成的函数对内置类型的成员不会处理(有些高版本编译器会处理,且C++11以后支持声明给缺省值),对自定义类型的成员会去调用对应的函数

​ ​   默认成员函数最大的用处就是自动调用,我们在C语言中写栈、顺序表的时候经常忘记初始化和置空,而默认成员函数很好的解决了这一点,只需要执行代码,之后的初始化和置空等操作都是自动进行,我们就不需要再去手动完成。

​   下面开始依次介绍默认成员函数🧐

构造函数🤔

​   构造函数是特殊的成员函数,它主要用于初始化对象,其特征为:

  1. 函数名与类名相同
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 可以对其重载

​   如下图,对象d1在没有调用Date函数的情况下,自动完成了初始化。

image-20240712201634395

​   并且在C++11后的版本,支持内置类型给全省值

Pasted image 20240708203532

​   注意,以下写法是错误的,因为编译器不知道是声明还是创建对象

image-20240714135000289

​   对于内置类型,编译器不会处理,而自定义类型编译器会去调用该类型的默认构造,如果没有默认构造就会报错。

Pasted image 20240708204153

​   最后,默认构造函数只能存在一个(不包括重载):全缺省构造函数,无参构造函数,没写自动生成的构造函数,如果写了构造函数,那么将不再自动生成。

析构函数🤔

​   析构函数与构造函数功能相反,用于对象的销毁,当对象生命周期结束时会自动调用析构函数,完成资源清理的工作,它的特征为:

  1. 析构函数要在类名前加上~
  2. 无参无返回值
  3. 一个类仅有一个析构函数,且不能重载
  4. 对象声生命周期结束时会自动调用析构函数
  5. 先定义的对象后清理(定义对象需要建立栈帧,栈的结构为先进后出)

​   如下图析构函数的自动调用实例,构造函数初始化a,析构函数将a置空

image-20240714144636239

image-20240714142826724

​   默认析构函数与构造函数相同,对内置类型不处理,自定义类型会调用该类型的析构函数。 ​ Pasted image 20240708232450

​   注意:析构函数在下图情况会崩溃,原因是没有写拷贝构造,导致这里的赋值是直接将地址传给st2,造成浅拷贝。st1和st2共用一个空间,当两个对象生命周期结束时,st2会先进行析构,此时空间被销毁了,st1再去析构就访问到野指针,故程序崩溃。

image-20240714150656612

image-20240714145311460

拷贝构造🤔

​   拷贝构造函数也是特殊的成员函数,特征如下:

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

  2. 拷贝构造的参数只有一个,且只能是类类型对象的引用,如果不加引用会导致无穷递归(传参生成临时变量,临时变量接收参数,此时就是拷贝,拷贝又会去调用拷贝构造,造成套娃)

      两种拷贝方式

    Pasted image 20240710125300

  ​ 参考栈的拷贝构造,我们建立一个新的空间,再将数据全部赋过去,st1和st2就成了两个独立空间,再进行析构就没有问题了。

image-20240714150912051

image-20240714150927735

​   拷贝构造对内置类型浅拷贝,自定义类型会调用该类型的拷贝构造。赋值是两个存在的对象进行拷贝,拷贝构造是一个已经存在的对象去初始化另一个要创建的对象

运算符重载🤔

​   运算符无法识别非内置类型之间的比较,这时运算符重载就派上用场了

image-20240714152332580

​   运算符重载需要用到关键字operator,其格式为(const可加可不加,后面会介绍):

返回值 operator运算符(参数)
{
    //...
}
//如
bool operator<(Date& d)
{
    //...
}

image-20240714152530955

​   运算符重载的特性为:

  1. 不能自己创建C++没有的操作符,比如operator@
  2. 用于内置类型的运算符,含义无法改变
  3. 重载操作符必须有一个类类型参数(在类中有this作为类类型参数)
  4. 作为类成员函数重载时,形参看起来比操作数少,是因为成员函数的第一个参数为隐藏的this
  5. .* sizeof . ?: ::五个运算符不能重载

取地址运算符的重载(const和非const)🤔

​   取地址(&)运算符其实也无法识别非内置类型,但是编译器将其函数加入了默认成员函数,所以我们可以不写也能使用该运算符。但是当我们不想让别人取到对象的地址时,就可以手动写对其修改。如下图我们传回nullptr,那么别人就拿不到对象的地址了。

Date* Date::operator&()
{
	return nullptr; //传回空 
}

const Date* Date::operator&() const
{
	return this; //传回地址
}

image-20240714154336354>
​   此外,如果对象被const修饰,那么就会调用const版取地址运算符的重载

image-20240714155931678

​   注意:这里流插入运算符是重载后才能使用,代码如下:

ostream& operator<<(ostream& out, const Date& d) //双操作数,左操作数为第一个参数,成员函数this只能在第一位,所以不能在类里面定义
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

成员函数const的用法🤔

​   在成员函数中,由于this指针是隐式的,且无法显式的写出来,所以当我们传给成员函数一个const修饰的对象就会出现这个问题:

void Print()
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

image-20240714160819127

​   Print接收的是Date* this的参数,但我们传过去的是const Date*,属于权限放大。因为无法在参数中修饰this指针,所以C++的做法就是把const放在函数名之后作为this的修饰。

void Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

image-20240714161500637

​   并且,只读函数加上const读写分离能够更好的保护数据

结尾👍

  以上便是六大成员函数的介绍,如果有疑问或者建议都可以私信笔者交流,大家互相学习,互相进步!🌹

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A.A呐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值