C++深入类与对象

article/2025/6/17 1:19:07

在上一篇中提到了构造函数,那么这篇再来提一下构造函数,编译器自动生成的默认构造函数对于内置类型不做处理,自定义类型会调用它自己的构造函数。对于自己写的构造函数,之前是在函数体中初始化,当然不止这一种初始化,还有初始化列表的方式进行初始化,那么为什么可以在函数体中初始化还需要初始化列表呢?咱接着往下看!

目录

构造函数:初始化列表

explicit关键字 

Static成员 

友元 

友元函数

 友元类

内部类 


构造函数:初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括 号中的初始值或表达式。

class Date{public:Date(int year, int month, int day): _year(year), _month(month),_day(day){}private:int _year;int _month;int _day;};

以日期类来看,在之前是在函数体中对对象的成员进行赋值,而初始化列表和其有一样的作用,当然只看初始化内置类型肯定是不行,这样觉得和在函数体中初始化没什么区别,那么如果是对自定义类型和const修饰类型和引用呢,在函数体中还能初始化吗?

对于自定义类型,初始化列表时可以自己写也可以不写,因为编译器会自动调用自定义类型自己的构造函数进行初始化。const修饰的变量和引用在定义时就需要初始化,而如果是在函数体中去初始化是会报错的,所以只能使用初始化列表来对其初始化。

示例:

class A
{
public:A(int a):_a(1){cout << "A" << endl;}
private:int _a;
};class B {
public:B(int a, int& ref):_ref(ref),_n(a),_ab(a){}
private:A _ab;//特征: 必须在定义的时候初始化int& _ref;const int _n;
};
int main()
{int n = 10;B a(10, n);return 0;
}

在这段代码中有自定义类型,引用,const成员变量三个成员变量, 那么我们看一下是否对其初始化了:

 通过调试可以看出是我们想要的结果。

需要注意的是:

1. 每个成员变量在初始化列表中最多只能出现一次(初始化只能初始化一次)

2. 类中包含以下成员,必须放在初始化列表位置进行初始化:

引用成员变量

const成员变量

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

3、尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化。

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();
}

各位可以看看输出结果是什么? 先说答案 输出结果为1 和随机值 ,那么为什么是1和随机值呢?

这就和初始化的顺序有关了,初始化列表初始化的顺序和初始化列表中的顺序无关,而是和声明的顺序有关 ,在这题中,_a2先声明,所以初始化时先对_a2初始化,但是在初始化列表中把_a1 的值给了_a2,所以_a2为随机值,在对_a1初始化,所以_a1的值为1。

运行结果:

explicit关键字 

构造函数不仅可以构造与初始化对象,对于接收单个参数的构造函数,还具有类型转换的作用。接收单个参 数的构造函数具体表现:

1. 构造函数只有一个参数

2. 构造函数有多个参数,除第一个参数没有默认值外,其余参数都有默认值

3. 全缺省构造函数

示例:

class A{public:/*explicit A(int a):_a(a){cout << "A(int a)" << endl;}*/A(int a):_a(a){cout << "A(int a)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}private:int _a;};int main(){A aa1(1);A aa2 = 2;return 0;}

在没有explicit修饰的情况下,A aa2 = 2 会进行隐式类型转换,整型转换为自定义类型,2构造一个A的临时对象(临时对象具有常性),临时对象再拷贝构造aa2 -->优化用2直接构造。

在explicit修饰的情况下,以上转换就不能进行。

运行结果:

Static成员 

概念:声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的 成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化。

 示例:

class A
{
public:A() { ++_scount; }A(const A& t) { ++_scount; }~A() { --_scount; }static int GetACount() { return _scount; }
private:static int _scount;
};int A::_scount = 0;void TestA()
{cout << A::GetACount() << endl;A a1, a2;A a3(a1);cout << A::GetACount() << endl;
}

静态成员变量需要在类外面定义,想要不通过对象来访问成员函数可以用static来修饰成员函数,就可以访问该成员函数。 

特性:

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

2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明

3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问

4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员

5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制 

友元 

友元函数

在实现日期类时,对于输入输出日期不能简单的使用流提取和流插入,而是需要重载该两个运算符,因为正常的流提取和流插入达不到预期效果。cout的输出流对 象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用 中cout需要是第一个形参对象,才能正常使用。所以要将operator重载成全局函数。但又会导致类外没办 法访问成员,此时就需要友元来解决。

示例:

class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}int main()
{Date d;cin >> d;cout << d << endl;return 0;
}

上述代码对<< 和>> 重载来实现日期类的输入输出,在类中声明两个函数为友元函数,便可以访问类的私有成员变量 。

注意:

友元函数可访问类的私有和保护成员,但不是类的成员函数

友元函数不能用const修饰

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

一个函数可以是多个类的友元函数

友元函数的调用与普通函数的调用原理相同

 友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

友元关系是单向的,不具有交换性。 友元关系不能传递 如果B是A的友元,C是B的友元,则不能说明C时A的友元。

友元类的声明和友元函数的声明一样,加friend修饰。

内部类 

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外 部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

内部类是外部类的天生友元,内部类可以访问外部类的私有变量,但是外部类不可以访问内部类的私有变量。

特性:

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

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

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

示例:

class A {
public:class B {public:void Fun(const A& a){cout << a._a << endl;}};
private:int _a;
};int main()
{A::B bb;bb.Fun(A());
}

http://www.hkcw.cn/article/NBXpxUKULx.shtml

相关文章

创新型老年综合评估实训室建设方案:提升评估实训精准性

随着人口老龄化加剧&#xff0c;老年综合评估人才需求激增&#xff0c;建设创新型老年综合评估实训室&#xff0c;是提升评估实训精准性、培育专业人才的关键路径。点击获取实训室建设方案 一、建设背景与意义 &#xff08;一&#xff09;行业发展需求 1、老龄化社会对老年综…

凤凰古城举行端午抢鸭子活动 欢乐江中庆佳节

5月31日,湖南凤凰古城沱江上举行了一场备受期待的“抢鸭子”大赛。500只精心挑选的鸭子被投入江中,其中一些鸭子颈项间系着鲜艳红绸带,象征好运。随着一声悠长的吆喝声响起,早已准备好的参赛者们纷纷跃入清凉的江水中。现场瞬间变成了欢乐的海洋,游客和市民一同沉浸在浓厚…

【深度学习】16. Deep Generative Models:生成对抗网络(GAN)

Deep Generative Models&#xff1a;生成对抗网络&#xff08;GAN&#xff09; 什么是生成建模&#xff08;Generative Modeling&#xff09; 生成模型的主要目标是从数据中学习其分布&#xff0c;从而具备“生成”数据的能力。两个关键任务&#xff1a; 密度估计&#xff0…

卢伟冰:诋毁本身就是一种仰望 小米汽车成功之道

小米集团合伙人、总裁卢伟冰昨晚谈到了小米汽车的成功。他表示,无论是SU7的热销还是YU7获得更高关注和期待,都基于强大的产品力。小米以“十倍投入做一辆好车”的决心,赢得了千万网友的认可。卢伟冰强调,小米汽车的成功体现了小米的价值观、模式和方法论。他还引用了莫言的…

西安交大原校长徐通模逝世 沉痛悼念与缅怀

沉痛悼念并深切缅怀徐通模同志。中国共产党优秀党员、西安交通大学原校长、我国动力工程与工程热物理领域著名专家、西安交通大学能源与动力工程学院热能工程系徐通模教授,因病医治无效,于2025年5月31日下午14时16分在西安逝世,享年86岁。徐通模同志1939年11月生于江苏如皋,…

性能优化 - 理论篇:常见指标及切入点

文章目录 引言一、 Java 性能优化的核心思路二、为什么要度量&#xff1f;三、常用性能衡量指标详解3.1 吞吐量与响应速度3.2 响应时间的具体度量&#xff1a;平均响应时间与百分位数3.3 并发量3.4 秒开率&#xff08;页面秒开&#xff09;3.5 正确性&#xff08;功能可用性&am…

Java代码重构:如何提升项目的可维护性和扩展性?

Java代码重构&#xff1a;如何提升项目的可维护性和扩展性&#xff1f; 在Java开发领域&#xff0c;随着项目规模的不断扩大和业务需求的频繁变更&#xff0c;代码的可维护性和扩展性逐渐成为了项目成功的关键因素。代码重构作为一种优化代码质量的重要手段&#xff0c;能够在…

【数据集】全球无缝高分辨率1 km 月均地表温度和气温(2001-2020)

目录 数据概述一、输入数据(Input Data)二、模型处理(Modeling and Processing)2.1 清空缺值重建(Clear-sky Ts Reconstruction)2.2 多云条件下地表温度重建(Cloudy-sky Ts Reconstruction)2.3 近地表气温估算(Ta Estimation)2.4 准确性验证与对比三、输出结果与产品…

Vue能启动但访问空白?并报”export ‘default’ (imported as ‘Vue’) was not found in ‘vue’

场景 如图&#xff0c;vue项目的node_modules下载顺利&#xff0c;启动也顺利&#xff0c;但是访问却为空白页面 虽然页面是空白&#xff0c;但是通过浏览器控制台可以看出并非简单的空白&#xff0c;确实有不兼容问题在里面 分析问题 从上图浏览器控制台可以看出&#xff0c…

go|channel源码分析

文章目录 channelhchanmakechanchansendchanrecvcomplieclosechan channel 先看一下源码中的说明 At least one of c.sendq and c.recvq is empty, except for the case of an unbuffered channel with a single goroutine blocked on it for both sending and receiving usin…

詹俊:国米表现太糟糕了,统治力差距明显

在欧冠决赛中,巴黎圣日耳曼对阵国际米兰,半场结束时巴黎以2-0领先。知名解说员詹俊对比赛进行了点评。詹俊指出,国米差点三球落后,他们在中前场缺乏逼抢力度,使得大巴黎能够轻松控球并通过短传渗透轻易进入进攻区域。大巴黎不仅擅长传控还能快速反击,展现了强大的统治力。…

黄健翔谈大巴黎5-0国米夺欧冠冠军 比赛成一边倒态势

6月1日凌晨,欧冠决赛落幕,巴黎圣日耳曼以5-0战胜国际米兰。赛后,黄健翔在社交媒体上分享了他的看法。他提到自己在赶往机场的途中,边吃早餐边回想刚结束的比赛。他对国米本场比赛的表现感到困惑,特别想了解国米在这场比赛中的战术策略究竟是如何制定的,导致全队多个位置和…

【KWDB 创作者计划】_探秘浪潮KWDB数据库:从时间索引到前沿技术

探秘浪潮KWDB数据库&#xff1a;从时间索引到前沿技术 文章目录 探秘浪潮KWDB数据库&#xff1a;从时间索引到前沿技术引言1.浪潮KWDB数据库时间索引深度解析1.1时间索引工作原理1.2时间索引创建与管理实践 2.浪潮KWDB数据库前沿产品技术纵览2.1多模融合存储引擎2.2就地计算技术…

Linux系统-基本指令(4)

文章目录 touch 指令&#xff08;2-2.25.00&#xff09;知识点&#xff08;普通文件和文本文件&#xff09;mkdir 指令知识点&#xff08;tree指令&#xff09;rm 指令man 指令&#xff08;3-0.00.00&#xff09;知识点&#xff08;Linux下&#xff0c;一切皆为文件&#xff09…

光电设计大赛智能车激光对抗方案分享:低成本高效备赛攻略

一、赛题核心难点与备赛痛点解析 全国大学生光电设计竞赛的 “智能车激光对抗” 赛题&#xff0c;要求参赛队伍设计具备激光对抗功能的智能小车&#xff0c;需实现光电避障、目标识别、轨迹规划及激光精准打击等核心功能。从历年参赛情况看&#xff0c;选手普遍面临三大挑战&a…

力扣 208.实现Trie(前缀树)

文章目录 题目介绍题解 题目介绍 题解 解析&#xff1a; 初始化&#xff1a;创建一棵 26 叉树&#xff0c;一开始只有一个根节点 root。26 叉树的每个节点包含一个长为 26 的儿子节点列表 son&#xff0c;以及一个布尔值 end&#xff0c;表示是否为终止节点。 insert&#xf…

WiFi万能钥匙鲲鹏服务器部署 TiDB 集群实战指南

作者&#xff1a; TiDBer_yangxi 原文来源&#xff1a; https://tidb.net/blog/15a234d0 一、环境准备 1. 硬件要求 服务器架构 &#xff1a;鲲鹏服务器&#xff08;ARM架构&#xff09;&#xff0c;TiDB 官方明确支持 ARM 架构服务器部署 推荐配置 &#xff08;生产环…

Java多线程并发常见问题与解决方案

1. 使用不当:竞争与死锁 synchronized保证了同一时刻只有一个线程访问同步块,但过度使用会导致线程争用、性能瓶颈,甚至死锁。当多个线程在不同顺序上请求多个锁时,容易产生循环等待而死锁。 下面示例演示了两个线程互相持有对方需要的锁导致的死锁情况: Object lockA…

Vue 核心技术与实战day06

1. 路由进阶 1.1 路由的封装抽离 1.21 声明式导航 - 导航链接 1.22 声明式导航 - 两个类名 1.23 声明式导航 - 两个类名 import Find from /views/Find import My from /views/My import Friend from /views/Friendimport Vue from vue import VueRouter from vue-router Vue.…

通信接口 之 串口通信

文章目录 通信接口串口通信硬件电路电平标准串口参数及时序串口时序 通信接口 通信协议及特征 通信目的&#xff1a;将一个设备数据传送到另一个设备&#xff0c;扩展硬件系统&#xff0c;如 STM32 外挂芯片需通信实现数据交换和控制。通信协议作用&#xff1a;制定通信规则&…