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

C++?类和对象(下)!!!

一、前言

        在之前我们已经讨论过了有关类和对象的前置知识以及类中的六大默认成员函数,在本期我们继续再讨论类和对象中剩余的友元、初始化列表等相关知识,如果需要再了解之前的知识的话,链接奉上:C++?类和对象(中)!!!-CSDN博客、C++?类和对象(上)!!!-CSDN博客,欢迎阅读!

二、再谈构造函数

        1、初始化列表

                (1).引入

        ·        之前我们已经在构造函数部分讨论过有关初始化的内容了,我们知道,构造函数可以完成在实例化对象的同时初始化对象属性的工作了,那么为什么还要引入初始化列表的概念呢?事实上,在构造函数体内赋值不是真正的初始化,这是因为函数体内赋值可以多次赋值,但是初始化时只能初始化一次的,同时类中有以下几类成员时构造函数体内赋值是不能完成的:
                        a.引用成员变量

                        b.const成员变量

                        c.自定义类型成员(同时该类没有默认构造函数)

                观察可以发现,以上三种成员的共同点是在变量实例化的同时就必须进行初始化。

                (2).介绍初始化列表

                        (2).1.初始化列表的语法是:在构造函数名之后,以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量之后跟一个放在括号内的初始值或者表达式,如下:
                        

                        (2).2.每个成员在初始化列表只能初始化一次

                        (2).3.尽量使用初始化列表进行初始化,因为不论在函数体内是否进行赋值,成员都会先经过初始化列表,事实上,调用默认构造函数、将成员变量的缺省值初始化赋值给成员这些工作都是在初始化列表隐式进行的

                        (2).4.成员变量在类中声明的次序就是它们在初始化列表中初始化的次序,与它们在初始化列表中的位置无关,下面的代码以及运行结果可以说明这个问题:
                        代码:      

class A{public:A(int a):_a1(a),_a2(_a1){}void Print() {cout<<_a1<<" "<<_a2<<endl;}private:int _a2;int _a1;};int main() {A aa(1);aa.Print();}

                        运行结果:
                        

                        以上运行结果就是因为先用一个随机值初始化了_a2,再用1初始化了_a1,导致最终产生以上运行结果

                        (2).5.同时在初始化列表可以初始化const类型、引用类型、没有默认构造函数的自定义类型:
                        

        2、explicit关键字

                构造函数不仅可以构造、初始化对象,对于接受单个参数的构造函数,还具有隐式类型转换的功能,接受单个参数的构造函数的都有:
                a.构造函数只有一个参数

                b.构造函数虽然有多个参数,但是除了第一个之外全都有缺省值

                c.全缺省的构造函数

                见如下代码:
                                

                可以观察到,以上代码中将2020这一int类型直接赋值给了Date类型,事实上在这个过程中,2020这一整型调用了构造函数,利用构造函数的隐式类型转换性质构造了一个临时的日期类对象,然后调用拷贝构造函数,对d完成了初始化,但是由于连续两次构造太浪费,所以编译器一般会优化掉,直接使用2020对d进行拷贝构造

                这时候如果使用explicit关键字修饰构造函数,构造函数就失去了隐式类型转换的功能,这时候就会报错。

三、static成员

        1、概念

        声明为static的类成员变量、用static修饰的成员函数,分别称为静态成员变量,静态成员函数,静态成员变量一定要在类外进行初始化。

        2、特性

                (1).静态成员为所有类对象共享,不属于某一个具体的对象,存放在静态区

                (2).静态成员变量必须在类外进行初始化,定义时不加static关键字,类中的只是声明、

                (3).类的公有静态成员可以使用类名::静态成员或者类对象.静态成员访问

                (4).静态成员函数没有隐式的this指针,不能访问非静态成员

                (5).静态成员也是成员,受访问限定符的限制

        3、应用

        下面的代码巧妙的利用了静态成员的特点,可以求出程序中共创建了多少类对象:
                

四、友元

        友元是一种突破封装的方式,可以为我们提供不少方便,但同时又因为它突破了封装,所以带来了一定的风险,不能多用。

        友元分为:友元函数和友元类

        1、友元函数

                (1).引入

                我们现在要尝试重载operator<<,发现这样一个问题:我们不能将<<重载为一个成员函数,这是因为我们希望<<操作符的左操作数是ostream类型,但是由于this指针一定占用形参的第一个位置,所以只能将<<重载为全局函数,看下面的代码:
                

                可以看到在上面我们在全局重载了<<操作符,但是报了错,这是因为日期类中的成员变量都是私有的,怎么办呢?这时候就要使用我们接下来要讨论的友元函数了。

                (2).介绍

                        (2).1.友元函数可以直接访问类的私有成员,它是定义在类外的普通函数,不属于任何类,在类中声明时要加friend关键字,借用类的友元函数这一特性,我们就可以解决上面的重载<<操作符的问题了:

                        

                        可以观察到,在将<<操作符重载声明为日期类的友元函数时,没有报错,这时候,<<操作符重载就可以访问日期类的私有成员变量了

                        (2).2.友元函数不可以用const修饰,这是由于const修饰的是成员函数隐藏的this指针,友元函数只是一个普通函数,没有this指针

                        (2).3.友元函数可以在类的任何地方声明,不受访问限定符的限制

                        (2).4.一个函数可以是多个类的友元函数

                        (2).5.友元函数与普通函数的调用原理相同

        2、友元类

                友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类的非公有成员,对于友元类需要注意:
                友元关系是单向的,不具有交换性、传递性,同时也不可以继承,这一点在在以后继承的位置详细介绍

                以下的日期类Date就是时间类Time的友元类,在日期类中可以直接访问时间类中的非共有成员:
                

class Time
{friend class Date;
public:Time(int hour = 1, int minute):_hour(hour),_minute(minute){}
private:int _hour;int _minute;
};class Date
{
public:Date(){_year = 1;_month = 1;_day = 1;}void time(int hour, int minute){_t._hour = hour;_t._minute = minute;}private:int _year;int _month;int _day;Time _t;
};

五、内部类

        1、概念

        如果一个类定义在另一个类内部,这个内部类就叫做外部类的内部类,内部类天然是外部类的友元类,可以在内部类中访问外部类的非公有成员,但外部类不可以访问内部类的非公有成员,外部类对于内部类没有任何特权。

        2、特性

                (1).内部类可以定义在外部类的public、protected、private都是可以的

                (2).内部类可以直接访问外部类的static成员,不需要外部类的对象/类名

                (3).sizeof(外部类) == 外部类,与内部类没有任何关系

六、结语

         这就是本期关于C++类和对象(下)的所有内容了,希望对大家有所帮助,感谢各位于晏、亦菲的阅读,欢迎大家和我一起讨论、进步。

        
                        

http://www.xdnf.cn/news/156187.html

相关文章:

  • 精益数据分析(27/126):剖析用户价值与商业模式拼图
  • 观察者模式 (Observer Pattern)
  • 游戏引擎学习第246天:将 Worker 上下文移到主线程创建
  • 如何给GitHub项目提PR(踩坑记录
  • windows下查看idea运行的进程占的JVM情况工具
  • olama部署deepseek模型
  • 从后端研发角度出发,使用k8s部署业务系统
  • gradle-缓存、依赖、初始化脚本、仓库配置目录详解
  • SpringBoot实现的后端开发
  • Ubuntu20.04 Ollama 配置相关
  • c++初始化数组
  • C语言中位段的应用
  • 【教程】Docker运行gitlab容器
  • 数据结构和算法(八)--2-3查找树
  • 什么时候使用Python 虚拟环境(venv)而不用conda
  • Qt软件开发-摄像头检测使用软件V1.1
  • python 与Redis操作整理
  • 血泪之arduino库文件找不到ArduinoJSON.h: No such file or directory错误原因
  • 学习记录:DAY18
  • AI日报 - 2025年04月26日
  • Yocto项目实战教程-第8章-树莓派启动定制镜像-8.4小节-使用Wic工具创建分区镜像
  • 毕业项目-基于java的入侵检测与防御系统
  • 字节 AI 原生 IDE Trae 发布 v1.3.0,新增 MCP 支持
  • 使用MyBatis注解方式的完整示例,涵盖CRUD、动态SQL、分页、事务管理等场景,并附详细注释和对比表格
  • Java爬虫入门:从网页抓取到数据提取(正则表达式篇)
  • 单例设计模式之懒汉式以及线程安全问题
  • 【计算机视觉】CV项目实战- 深度解析TorchVision_Maskrcnn:基于PyTorch的实例分割实战指南
  • 从“拼凑”到“构建”:大语言模型系统设计指南!
  • 【Vue】Vue3项目创建
  • 美团Java后端二面面经!