C++初阶:类与对象(尾篇)
目录
- 1. 构造函数与初始化列表
- 1.1 对象的创建与构造函数的初始化
- 1.2 初始化列表及构造函数存在的意义
- 1.3 explicit关键字与构造函数的类型转换
- 2. static成员变量与static成员函数
- 2.1 static成员变量
- 2.2 static成员函数
- 3. 日期类流插入操作符的重载与友元
- 3.1 友元
- 3.2 友元函数
- 3.3 友元类
- 4. 内部类
- 5. 匿名对象
- 6. 拷贝对象时编译器可能会进行的一些优化
1. 构造函数与初始化列表
1.1 对象的创建与构造函数的初始化
- 在前面的学习中,我们尝试了对简单类(日期类)进行了实现,而后在使用中我们通过定义类模板然后实例化的方式,创建我们所需要的对象。
- 在这一过程中,编译器按照所指定的类型去相应的内存区域中申请空间,在已经创建好变量后,再调用构造函数对生成的对象进行初始化。
- 大多数情况下,这种初始化的方式都不会出现问题,可是当类的成员变量中有一些特定的类型比如,const修饰的变量,引用类型的变量,没有默认构造函数的自定义类型,此时,这种初始化方式就行不通了。(默认构造函数:编译器自动生成,无参数,有缺省参数)
1.2 初始化列表及构造函数存在的意义
- 内置类型可以在创建变量申请空间时就进行变量的初始化,而自定义类型是否也可以在创建变量的同时就进行初始化,它的初始化方式是什么,接下来,我们引出类与对象中的初始化列表。
- 类实例化生成对象时并不是只开辟空间,对空间中的内容不做处理,而是会调用初始化列表对开辟出的空间进行初始化。前面之所以无法对特殊类型无法进行初始化,是因为我们没有向初始化列表中添加内容。
- 初始化列表的定义方式:
//构造函数
class A
{
private:int _a;int _b;int _c//构造函数,函数体之前,语法如下:A(int a, int b ,int c):_a(a),_b(b),_c(c){}
}
- 初始化列表的调用方式:(三种必须用初始化列表进行初始化的成员变量)
//没有缺省参数
class A
{
public:A(int d){_d = d;}int _d;
};class B
{
public:const int _a;int& _b;A _c;//构造函数B(int b, int c):_a(10),_b(b),_c(c){cout << " _a = " << _a << " _b = " << _b << " _c._d = " << _c._d << endl;}
};int main()
{int b = 20;int c = 30;B a(b, c);return 0
}
- 初始化列表初始化成员变量的顺序:
初始化列表进行初始化的顺序是根据成员变量的声明顺序决定的
class A
{
public:int _b;int _a;//先初始化_a,再初始化_bA(int a = 0):_a(a),_b(_a){}void Print(){cout << _a << ' ' << _b << ' ' << endl;}
};int main()
{A a(10);a.Print();return 0;
}
执行结果:使用成员变量_a初始化成员变量_b时,_a还没有被初始化
- <1> 既然初始化列表可以进行初始化,并且初始化列表能做到构造函数无法做到的特殊类型成员的声明,那么,为什么还要有构造函数呢?
<2> 初始化列表能做的只有初始化,无法对初始化后的变量做检查与合法性判断
class A
{
public:int* _a;A(int n):_a((int*)malloc(n * sizeof(int))){if (_a == nullptr){perror("malloc failed");exit(-1);}}
};
1.3 explicit关键字与构造函数的类型转换
- 类的默认成员函数
operator=重载
,其构造函数在只有单参数或拥有缺省参数,支持用与成员变量类型相同的数据,变量直接进行赋值操作。
class Date
{
public:int _year;int _month;int _day;Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
};int main()
{Date d1(2024);d1 = 2025;int year = 2026;d1 = year;cout << d1._year << '-' << d1._month << '-' << d1._day << endl;return 0;
}
支持上述操作的原因,是因为数据或者变量会进行类型转换构造临时对象,然后再用临时构造出的对象进行赋值操作。
explicit
关键字,修饰构造函数,使得这个构造函数所在的类其,实例化的对象不会发生类型转换的操作。
class Date
{
public:int _year;int _month;int _day;explicit Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}
};
2. static成员变量与static成员函数
2.1 static成员变量
- 静态成员变量也是类的成员之一,它不独属于某个对象,而是属于这个类,为所有实例化对象所共有,存放在静态区。
- 静态成员变量在类中声明,在类外定义,在类外定义时不需要加static关键字。
- 静态成员变量的调用方式为,
对象.静态成员变量
,类区域::静态成员变量
- 静态成员变量也受访问限定符的限制
class A
{
public:static int _count;A(){++_count;}A(const A& a){++_count;}~A(){--_count;}
};int A::_count = 0;int main()
{A a1;cout << a1._count << endl;a1.~A();cout << A::_count << endl;return 0;
}
2.2 static成员函数
- 与静态成员变量类似,静态成员函数也是属于全体实例化对象,而不是属于某个对象。
- 静态成员函数的定义方式,也是类内声明类外定义。
- 静态成员函数没有this指针,不能调用非静态成员变量。
- 静态成员函数的调用方式,
对象.静态成员函数
,类域::静态成员函数
- 同样的静态成员函数也受访问限定符限制。
class A
{
//public:static int _count;static int GetCount();
public://非静态成员函数可以调用静态成员函数void Print(){cout << (*this).GetCount() << endl;cout << "hello" << endl;}A(){++_count;}A(const A& a){++_count;}~A(){--_count;}
};int A::_count = 0;
int A::GetCount()
{//静态成员函数没有this指针//无法调用非静态成员函数return A::_count;
}
3. 日期类流插入操作符的重载与友元
- 当我们尝试对实现过的日期类进行流插入运算的重载时,当把它作为成员函数时,我们发现无法实现。
- 操作数的次序为操作符重载函数的参数从左往右,分别是操作符的第一个,第二个…操作数。
- 成员函数的一个参数都为隐藏的默认参数this指针,而流插入操作符的需要的第一个参数是ostream类型的变量。可是,当我们不使用成员函数的方式实现,那么函数就无法访问private访问限定符修饰的成员变量。
- 那么,流插入操作符的重载就无法实现吗,这里我们引入C++新的内容,友元。
3.1 友元
- 友元关系的实际应用分为友元类与友元函数,这是一种突破类访问限定符封装的方式,它在提供了这种功能的同时,也不可避免地增加了代码的耦合性,不建议多用。
3.2 友元函数
- 友元函数是普通函数,它定义在类外。而它达成友元的方式为,在类中对其进行友元声明。
- 友元函数可以在类中的任何地方声明,不受访问限定符影响。
- 友元函数的声明方式为,在普通的函数声明前加关键字
friend
。- 一个函数可以是多个类的友元函数。
class Date
{
public:int _year;int _month;int _day;Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& out, const Date& d);
};ostream& operator<<(ostream& out, const Date& d)
{out << d._year << '-' << d._month << '-' << d._day;return out;
}istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
3.3 友元类
- 友元类的所有成员函数都是另一个类的友元函数,可以访问另一个类的所有私有成员。
- 友元类关系是单向的。
- 友元关系不可传递,A类是B类友元,B类是C类的友元,A类不是C类的友元,不可以访问C类。
- 友元关系不能被继承
- 友元类的声明方式为,在需要被访问的类中声明其的友元类,
friend + 类名
。
class Time
{
public:Time(int hour = 0, int minute = 0, int seconds = 0):_hour(hour), _minute(minute), _seconds(seconds){}friend class Date;private:int _hour;int _minute;int _seconds;
};class Date
{
public:int _year;int _month;int _day;Time _t;Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}void SetTime(){_t._hour = 21;_t._minute = 25;_t._seconds = 0;cout << _t._hour << '/' << _t._minute << '/' << _t._seconds << endl;}
};
4. 内部类
- 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。
- 外部类对内部类没有访问权限。
- 内部类只是在外部类中声明,外部类计算大小时不包含内部。(sizeof(外部类)单纯只是外部类的大小)
- 内部类对外部类天生就是友元,并且可以直接访问外部类的静态成员变量与函数,无需指定类域。
- 内部类可以在任意访问限定符的区域声明,在private中时,无法进行内部类的调用实例化对象。
class A
{
private:int _a;static int _c;public:class B{public:void test(A& x){x._a = 10;_c = 20;cout << x._a << endl;cout << x._c << endl;}};
};int A::_c = 0;int main()
{A x;//內部类对象的声明A::B h;h.test(x);return 0;
}
5. 匿名对象
- 在实例化对象时,省略对象名的创建方式。
- 匿名对象的声明周期只有一行,紧接着下一行时,就会调用析构函数将其销毁。
class A
{
private:int _ a;
public:A(int a = 0){cout << _a << endl;}void Print(){cout << "hello world" << endl; }
};//不支持此种调用构造函数的方式,因为无法识别其为函数的声明还是析构函数的调用
A a1();//创建匿名对象的方式
A();//匿名对象调用成员函数
A().Print();
6. 拷贝对象时编译器可能会进行的一些优化
- 在成员函数传参和传返回值的过程中,一般编译器会做一些优化,减少不必要对象的拷贝
- 在同一行中,连续的构造,拷贝构造操作编译器会进行优化:(同一表达式中)
<1> 构造 + 拷贝构造 优化为 构造
<2> 构造 + 构造 优化为 构造
<3> 连续的拷贝构造 优化为 直接进行拷贝构造
(临时对象,匿名对象生命周期只有一行)
class C
{
private:int _c;
public:C(int c){cout << "C()" << endl;}C(const C& tmp){cout << "C(const C&)" << endl;}
};void f1(C aa)
{}C f2()
{C aa;return aa;
}int main()
{//构造 + 拷贝构造,类型转换,生成临时对象C c1(2);//构造 + 拷贝构造 => 构造f1(C(2));//连续的拷贝构造 =>直接进行拷贝构造C c3 = f2();//不会优化,需要引用中间变量const C& c4 = 2;//不会优化,没有在同一表达式中C c5(2);f1(c5);return 0;
}
补充练习:(内部类,访问限定符)
- 求n!
- 思路:创建对应数量的对象,在构造函数中++静态成员变量,使用静态成员变量计数
class Solution
{
private:static int _ret;static int _i;//将内部类定义在private下可保证不被非法访问class B{//默认为私有public:B(){_i++;_ret += _i;}};public:int Sum_Solution(int n) {//将类B设为公有,即可在外部类访问B arr[n];return _ret;}};int Solution::_i = 0;
int Solution::_ret = 0;
相关文章:

C++初阶:类与对象(尾篇)
目录 1. 构造函数与初始化列表1.1 对象的创建与构造函数的初始化1.2 初始化列表及构造函数存在的意义1.3 explicit关键字与构造函数的类型转换 2. static成员变量与static成员函数2.1 static成员变量2.2 static成员函数 3. 日期类流插入操作符的重载与友元3.1 友元3.2 友元函数…...

Spring状态机简单实现
一、什么是状态机 状态机,又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的计算模型。状态机的概念其实可以应用的各种领域,包括电子工程、语言学、哲学、生物学、数学和逻辑学等,例如日常生活中的电…...

WebServer -- 面试题(下)
👂 夏风 - Gifty - 单曲 - 网易云音乐 目录 🌼前言 🎂面试题(下) 4)HTTP报文解析 为什么要用状态机 状态转移图画一下 https 协议为什么安全 https 的 ssl 连接过程 GET 和 POST 的区别 5)数据库注册登录 登…...

企业微信如何接入第三方应用?
1.登录企业微信管理后台:https://work.weixin.qq.com/wework_admin 2.点击创建应用; 3. 此时可以看到已经创建好的应用,并且生成应用的唯一id(agentId) 4. 第三方应用申请域名 (举例&…...
JAVA后端编码的主键字段存储为什么倾向于使用雪花算法
1.背景 最近有人问,什么是雪花算法,为什么使用雪花算法不使用数据库UUID,基于此,写一个说明。 2.简介 (1)雪花算法,英文名为snowflake,翻译过来就是是雪花,所以叫雪花…...

Rust 深度学习库 Burn
一、概述 Burn 它是一个新的综合动态深度学习框架,使用 Rust 构建的,以极高的灵活性、计算效率和可移植性作为其主要目标。 Rust Burn 是一个以灵活性、高性能和易用性为核心设计原则工具,主打就是灵活性 、高性能 及易用性。 二、Rust B…...

C语言-存储期2.0
静态存储期 在数据段中分配的变量,统统拥有静态存储期,因此也都被称为静态变量。这里静态的含义,指的是这些变量的不会因为程序的运行而发生临时性的分配和释放,它们的生命周期是恒定的,跟整个程序一致。 静态变量包含…...
计算机网络面经八股-HTTP请求报文和响应报文的格式?
请求报文格式: 请求行(请求方法URI协议版本)请求头部空行请求主体 请求行:GET /sample.jsp HTTP/1.1 表示使用 GET 方法请求 /sample.jsp 资源,并使用 HTTP/1.1 协议。请求头部:包含多个字段,…...
Ubuntu 18.04安装最新版Visual Studio Code(VS Code)报依赖库版本过低错误
Ubuntu 18.04安装最新版Visual Studio Code(VS Code)报依赖库版本过低错误 1. 问题描述2. 解决方案2.1 修复之前安装的错误2.2 安装VS Code 1.85.2 3. 原因分析 1. 问题描述 在Ubuntu 18.04系统上安装VS Code ≥ v1.86.2(测试到v1.87.1&…...

Android NDK入门:在应用中加入C和C++的力量
目录 编辑 引 NDK的设计目的 与Java/Kotlin的结合 使用场景 开发流程 设置项目以支持NDK 编写本地代码 使用JNI连接本地代码和Java/Kotlin代码 编译和运行你的应用 附 引 自诩方向是android方向的移动端开发工程师,却从来没有真正仔细了解过NDK&#…...
2024年华为OD机试真题-田忌赛马-Java-OD统一考试(C卷)
题目描述: 给定两个只包含数字的数组a,b,调整数组 a 里面数字的顺序,使得尽可能多的 a[i] >b[i]。数组 a和 b 中的数字各不相同。 输出所有可以达到最优结果的 a 数组的数量 输入描述: 输入的第一行是数组 a 中的数字,其中只包含数字,每两个数字之间相隔一个空格,a…...

C++ 网络编程学习五
C网络编程学习五 网络结构的更新单例模式懒汉单例模式饿汉单例模式懒汉式指针智能指针设计单例类 服务器优雅退出asio的多线程模型IOServiceasio多线程IOThreadPoolepoll 和 iocp的一些知识点 网络结构的更新 asio网络层,会使用io_context进行数据封装,…...

案例分析篇05:数据库设计相关28个考点(9~16)(2024年软考高级系统架构设计师冲刺知识点总结系列文章)
专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…...

pip 和conda 更换镜像源介绍
1、前言 很多深度学习的项目免不了安装库文件、配置环境等等,如果利用官方提供的连接,网速很慢,而且很容易download掉。 所以配置好了虚拟环境,将pip换源属实重要 常见的国内镜像源有清华、中科大、阿里等等... 这里建议用中科…...

Git概述及安装步骤
一、Git简介 Git是一个免费的、开源的分布式版本控制系统,可以快速高效地处理从小型到大型的各种项目。Git 易于学习,占地面积小,性能极快。它具有廉价的本地库,方便的暂存区域和多个工作流分支等特性。其性能优于Subversion、CV…...

北京保险服务中心携手镜舟科技,助推新能源车险市场规范化
2022 年,一辆新能源汽车在泥泞的小路上不慎拖底,动力电池底壳受损,电池电量低。车主向保险公司报案,希望能够得到赔偿。然而,在定损过程中,保司发现这辆车的电池故障并非由拖底事件引起,而是由于…...

给女朋友的浪漫微信消息推送超详细版
1. 下载代码 地址: 链接: https://pan.baidu.com/s/1lESgRoWn8bXyE0jsSVCHqQ?pwdimr6 提取码: imr6 根据 resources/db 下sql文件创建表 修改yml文件中数据库连接 2. 进入微信测试平台 地址:微信公众平台 扫码登录获取测试号信息 修改代…...
Android开发 Activity启动模式、ViewModel与LiveData,及Kotlin Coroutines
目录 Activity启动模式 onNewIntent解释 Activity启动模式的考虑时机 Service启动模式 ContentProvider的作用 Broadcast的注册方式 AsyncTask的作用 ViewModel LiveData Kotlin Coroutines 结合使用 Activity启动模式 Android中Activity的启动模式有四种࿰…...
MQL语言实现抽象工厂模式
文章目录 一、定义抽象产品接口二、定义抽象工厂接口三、定义具体产品四、定义具体工厂五、定义工厂客户端六、客户端调用工厂客户端七、抽象工厂模式的结构 一、定义抽象产品接口 //------------------------------------------------------------------ //| participants …...

UE4开个头-简易小汽车
跟着谌嘉诚学的小Demo,记录一下 主要涉及到小白人上下车和镜头切换操作 1、动态演示效果 2、静态展示图片 3、蓝图-上下车...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...