4.类和对象
C++面向对象的三大特性为:封装、继承、多态。
C++认为万事万物都皆为对象,对象上有其属性和行为。
【注】具有相同性质的对象,我们可以抽象称为类。人属于人类,车属于车类。
(1)封装
①封装的意义
封装是C++面向对象三大特性之一。
封装的意义:
a.将属性和行为作为一个整体,表现生活中的事物;
b.将属性和行为加以权限控制。
【注】空类的大小是1,即占1个字节。
封装意义一:
在设计类的时候,属性和行为写在一起,表现事物。
语法:class 类名{ 访问权限:属性 / 行为 };
【注】实例化:通过一个类,创建一个对象的过程。
【注】类中的属性和行为 我们统一称为 成员;属性还可以称为成员属性或成员变量;行为还可以称为成员函数或成员方法。
封装意义二:
类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限有三种:
a. public //公共权限(类内可以访问,类外可以访问)
b. protected //保护权限(类内可以访问,类外不可以访问)(儿子可以访问父亲中的保护内容)
c. private //私有权限(类内可以访问,类外不可以访问)(儿子不可以访问父亲中的保护内容)
【注】类中的函数权限也是同样的道理:(函数体在类内均可以访问属性,类外则要根据权限访问)
②struct和class的区别
在C++中struct和class唯一的区别就在于:默认的访问权限不同。
区别:
struct默认权限为公共;
class默认权限为私有。
③成员属性设置为私有
优点1:将所有成员属性设置为私有,可以自己控制读写权限
优点2:对于写权限,我们可以检测数据的有效性
【注】在类中可以让另一个类 作为本来中的成员。
【注】一般编程过程中,类较多,会把类单独拿出来放在另一个文件中。
(2)对象的初始化和清理
(出厂设置)C++的每个面向对象,也都会有初始设置以及对象销毁前的清理数据的设置。
①构造函数和析构函数
对象的初始化(构造函数)和清理(析构函数)也是两个非常重要的安全问题:
a.一个对象或者变量没有初始状态,对其使用后果是未知;
b.同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题。
C++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。
对象的初始化和清理工作是编译器强制我们要做的事情,因此如果我们不提供构造和析构,编译器会提供。
编译器提供的构造函数和析构函数是空实现。
构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。
构造函数语法:类名(){ }
a.构造函数,没有返回值也不写void
b.函数名称与类名相同
c.构造函数可以有参数,因此可以发生重载
d.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
析构函数语法:~类名(){ }
a.析构函数,没有返回值也不写void
b.函数名称与类名相同,在名称前加上符号~
c.构造函数不可以有参数,因此不可以发生重载
d.程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
【注】“对象销毁前”指的是该行代码被释放后将要被销毁之前。
②构造函数的分类及调用
两种分类方式:
按参数分为:有参构造和无参构造(默认构造(默认情况下编译器会提供一个无参构造))
按类型分为:普通构造和拷贝构造
【注】拷贝构造函数中的数据类型要相同。
三种调用方式:
括号法
显示法
隐式转换法
a.对于括号法:
【注】调用默认构造函数时,不要加()
因为上面这行代码,编译器会认为是一个函数的声明,不会认为在创建对象。
b.对于显示法:
【注】
【注】不要利用拷贝函数来初始化匿名对象。
c.对于隐式转换法:
【总结】建议常用括号法。
③拷贝构造函数调用时机
C++中拷贝构造函数的调用时机通常有三种情况:
a.使用一个已经创建完毕的对象来初始化一个新对象
b.值传递的方式给函数参数传值(值传递会拷贝一个临时的副本出来)
c.以值方式返回局部对象
④构造函数调用规则
默认情况下,C++编译器至少给一个类添加3个函数:
a.默认构造函数(无参,函数体为空)
b.默认析构函数(无参,函数体为空)
c.默认拷贝构造函数,对属性进行值拷贝
【注】没有写拷贝构造函数时,编译器不会写28行的代码,但是会写27行的代码:
构造函数调用规则如下:
a.如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造;
b.如果用户定义拷贝构造函数,C++不会再提供其它构造函数。
【总结】提供有参,编译器不提供默认但提供拷贝;提供拷贝,编译器什么都不提供。
⑤深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝操作。
深拷贝:在堆区重新申请空间,进行拷贝操作。
【注】如果利用编译器提供的拷贝构造函数,会做浅拷贝操作。浅拷贝带来的问题就是:堆区的内存重复释放,导致非法操作。
浅拷贝的问题要利用深拷贝进行解决。
【注】析构代码的用处:
【总结】如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。
⑥初始化列表
C++提供了初始化列表语法,用来初始化属性。
语法:构造函数():属性1(值1),属性2(值2)…{ }
⑦类对象作为类成员
C++类中的成员可以是另一个类的对象,我们称该成员为 对象成员。
【注】当其他类的对象作为本类中的成员时,构造的时候先构造其他类中的对象,再构造自身。而析构函数的顺序与构造相反。
⑧静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员。
静态成员分为:
a.静态成员变量
所有对象共享同一份数据;
在编译阶段分配内存;
类内声明,类外初始化。
b.静态成员函数
所有对象共享同一个函数;
静态成员函数只能访问静态成员变量。
【注】Person::func(); //Person作用域下面的func函数
【注】静态成员函数也是有访问权限的,类外访问不到私有静态成员函数。
【注】静态成员变量有两种访问方式:通过对象访问和通过类名访问。
(3)C++对象模型和this指针
①成员变量和成员函数分开存储
在C++中,类内的成员变量和成员函数分开存储。
只有非静态成员变量才属于类的对象上。
【注】空对象占用内存空间为:1 ; 每个空对象也应该有一个独一无二的内存地址。
【注】C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置。
②this指针概念
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。那么,这一块代码是如何区分哪个对象调用自己呢·?
C++通过提供特殊的对象指针 this指针 来解决上述问题。this指针指向被调用的成员函数所属的对象。
this指针是隐含每一个非静态成员函数内的一种指针;
this指针不需要定义,直接使用即可。
this指针的用途:
a.当形参和成员变量同名时,可用this指针来区分;
b.在类的非静态成员函数中返回对象本身,可使用 return * this
【注】返回的应当是Person& ; 即返回的应当是引用。
【注】如果返回的不是引用,而是一个值(值传递),那么一定会创建一个新的对象(会调用拷贝构造函数)。
③空指针访问成员函数
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针。
如果用到this指针,需要加以判断以保证代码的健壮性。
④const修饰成员函数
常函数:
a.成员函数后加const后,我们称这个函数为常函数
b.常函数内不可以修改成员属性
c.成员属性声明时加关键字mutable后,在常函数中依然可以修改
【注】this的本质是一个指针常量(指向是不可以修改的,指向的值可以修改)
【注】加了const之后,成员函数变为常函数,如下图解释所说,指针指向的值也不能改。
【注】如果想在常函数中修改成员属性,则要在声明时在前面加上mutable
常对象:
a.声明对象前加const则称该对象为常对象
b.常对象只能调用常函数
【注】对于m_B来说,其声明时前面加了mutable,所以可以修改它的值:
【注】常对象只能调用常函数,不可以调用其他普通成员函数(假设能调用,相当于侧面可以修改m_A的值(普通成员函数可以修改属性),而这是不允许的):
(4)友元
在程序里,有些私有属性也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术。
友元的目的就是让一个函数或者类,访问另一个类中的私有成员。
友元的关键字为 friend
友元的三种实现:
a.全局函数做友元
b.类做友元
c.成员函数做友元
①全局函数做友元
如下图所示,此时全局函数并不能访问类中的私有成员:
但是在全局函数之前加上friend之后再放入类中,此时全局函数便可以访问私有成员:
②类做友元
假设A类要访问B类中的私有成员,那么在A类前面加上friend之后再放入B类中,如下图所示:
【注】如果要在类外写构造函数,要在函数名称前面加上作用域(::)。构造函数的声明依然写在类里。
③成员函数做友元
想让哪一个成员函数做友元,即可以访问类中的私有成员,就把在成员函数之前加上friend之后放入类中:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!