C++类和对象(下) 初始化列表 、static成员、友元、内部类等等

1.再探构造函数

  1. 之前使用构造函数时都是在函数体内初始化成员变量,还有一种构造函数的用法,叫做初始化列表;那么怎么使用呢?
    1. 使用方法用冒号开始(" : ")要写多个就用逗号(" , ")隔开数据成队列
    2. 每个成员变量后面跟着一个括号,括号内就是初始化的内容;括号内可以是初始值或者一个表达式
  2. 每个成员变量只要初始化一次就行了,不能重复初始化;这里也是成员变量定义的地方
  3. 引用成员变量、const成员变量、没有默认构造的类 类型变量,这三类必须在初始化列表位置进行初始化,否则会报错
  4. C++11支持在成员变量声明的位置给上缺省值,这里的缺省值是给初始化列表使用的,当没有显示写初始化列表就会用到缺省值
  5. 下列是思维动图形式的小总结
  6. 初始化列表中是按照成员变量声明处的顺序来进行初始化的,与初始化列表中写的先后顺序无关,所以建议声明的顺序和初始化列表的保持一致;当然也是和内存存储顺序有关(地址处低到高)
  7. 每个构造函数都有初始化列表,没有显示写会自动生成
  8. 补充:
    1. 函数的缺省值是提供给实参使用的,成员变量处的缺省值是提供给初始化列表使用的
    2. 调用函数建立栈帧时对象就会申请空间,构造函数是用来初始化的;两者之间要区分

#include<iostream>
using namespace std;class Date
{
public:Date(int day = 100){_day = day;}
private:int _day;
};
class A
{
public:A(int a = 1, int b = 1, int c = 1): _a(a), _b(b),_ca(c),_quote(a), _ptr((int*)malloc(12))//还可以是表达式{if (_ptr == nullptr){perror("_prt fail");}else{memset(_ptr, 1, 12);//给内存初始化为 全1}}void Print(){cout << _a << '/' << _b << '/' << _c << endl;}
private://声明int _a = 10; // 这里的是给初始化列表使用的缺省值int _b = 20;int _c = 30; //没有显示写时,缺省值就会用上int* _ptr;//下列的都必须使用初始化列表const int _ca;//必须要有初始化int& _quote;Date _ddy;// 没有默认构造会报错
};int main()
{A aa(2024,8,23);aa.Print();return 0;
}

2.类型转换

  1. C++支持内置类型隐式类型转换为类类型对象需要对应的内置类型为参数(实参)的构造函数
  2. 如果不需要隐式类型转换了,构造函数前面加explicit就不再支持隐式类型转换
  3. 类类型的对象之间也可以隐式转换,需要对应构造函数支持
class AB
{
public://explicit AB(char a = 0, char b = 0)AB(char a = 0,char b = 0){_a = a;//_b = b;}void Print(){cout << _a << _b << endl;}
private:char _a;char _b = 'b';
};
class Stack
{
public:Stack(){}void Push(const AB& abp){//...}
private:AB _arr[10];int _size;
};
int main()
{//隐式类型转换//65构造AB类的临时对象,然后用这个临时对象拷贝给au//编译器将 连续构造 + 拷贝构造 ,优化成直接构造AB au = 65;//AB au = "abcd";字符串不可以隐式类型转换au.Print();AB& aup = au;const AB& p = 2; // 2 会产生临时对象,具有常性,需要constStack st;AB aa1(60, 70);st.Push(aa1);AB aa2 = { 88,99 };//支持多参数// C++11 才支持的const AB& aa3 = { 77,78 };//上面的方法麻烦,还需要创建类再插入;这里可以直接插入//因为AB是多参数的st.Push({ 77,78 });return 0;
}

3.static成员

  1. 用static修饰的成员变量, 叫做静态成员变量,静态成员变量一定要在类外面初始化
  2. 静态成员变量为 所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区;当前同类型的对象也可以访问
  3. 被static修饰的成员函数,叫静态成员函数,静态成员函数是没有this指针的;如果要返回静态成员变量需要静态成员函数
  4. 静态成员函数中可以访问其他的静态成员,但是不能访问非静态成员,因为没有this指针
  5. 非静态的成员函数,可以任意访问静态成员函数和静态成员变量
  6. 突破类域的限制就可以访问静态成员,通过 fun3::Getb() 或者 fufu.Getb();就可以访问静态成员函数和静态成员变量
  7. 虽然可以任意访问静态成员,但静态成员也是类的成员,也会受到public、protected、private访问限定符的限制
  8. 静态成员变量,不走构造函数的初始化列表;因为不属于某一个类,自然给初始化列表的缺省值也不能用
class fun2
{
public:static int _aa;fun2(){}void sum(){_a--;}static int Geta()//不可以访问非静态的,非静态的可以访问静态的{_a += 2;return _a;//虽然都可以访问静态成员变量,但是正常情况下是需要this指针才能当作返回值//得出如果要返回静态成员变量需要静态成员函数}
private:static int _a;
};class fun3
{
public:static int Getb(){//调用函数 返回结果return fun2::Geta();//因为是静态函数所以都可访问,但也受访问限定符限制 }
private:static int _b;
};//在类外初始化
int fun3::_b = 30;int fun2::_aa = 22;
int fun2::_a = 10;
int main()
{int at = 1;fun2 f1;f1.sum();cout << fun2::Geta() << endl;//大小是1,标识这个对象,静态成员变量在静态区cout << sizeof(f1) << endl;//都可以访问静态函数cout << fun3::Getb() << endl;//所有类都可以访问,但是会受到类域限制cout << fun2::_aa << endl;//访问静态成员函数两种方式,常用 :: 符号访问fun3 fufu;cout << fun3::Getb() << endl;cout << fufu.Getb() << endl;return 0;
}

补充:

  1. 静态的变量第一次走到那里才会初始化;全局的静态会在,main函数之前初始化。
  2. 编译阶段会有语法检查;变量初始化时,如果不使用会被优化;

4.友元

  1. 友元提供一种突破类访问限定符封装的方式,友元分为:友元函数和友元类,在函数声明前面加上friend,把友元声明放到类里
  2. 外部的友元函数可以访问类的私有和保护成员,就是一个声明,不是类的成员,也不会占用额外空间
  3. 友元函数可以在类的任何地方定义,不受类访问限定符限制;一般都放到类的最开头
  4. 一个函数可以是多个类的友元函数
  5. 友元类中的成员函数都可以是另一个类的友元函数,可以访问另一个类的私有和保护
  6. 不过友元类是单向的,A类是B类的友元,但是B类不可以是A类的友元
  7. 友元类没有传递性,A类是B类的友元,B类可以是C类的友元,但是A类不可以是C类的友元;如果希望是那么在C类写上A类的友元声明
  8. 友元也有弊端,友元会增加耦合度,破坏了封装,尽量不用
//前置声明
void Print();
class yy
{//友元函数声明friend int sum(const yy& x1, const yy& x2);friend void Print();//友元类声明,单向的;yy类不可访问cl类friend class cl;
public:void print2(){Print();}
private:int _a = 10;int _b = 20;
};int sum(const yy& x1,const yy& x2)
{return x1._a + x2._b;
}void Print()
{cout << 11 << endl;
}class cl
{int sum1(const yy& x1, const yy& x2){return x1._a + x2._b;}int sum3(const yy& x1, const yy& x2){return x1._a + x2._b;}
};int main()
{yy x1, x2;int ret = sum(x1, x2);cout << ret << endl;//此时证明写了友元函数声明,可以双方互相访问x1.print2();return 0;
}

5.内部类

  1. 如果一个类定义在另一个类的内部,那么这个类就叫做内部类;内部类是一个独立的类(计算外部类的空间时,不会开辟内部类的),只受到访问限定符的限制和外部类的类域限制,所以外部类定义的对象中不包含内部类
  2. 内部类本质也是一种封装,但A类和B类达成合作关系(B类频繁使用A类),此时可以考虑写一个专属内部类,就是把A类放到private/protected位置;这样其他地方想创建A类,就创建不了
  3. 可以看看这题,更好的理解

#include <iostream>
using namespace std;
class A
{
public:void Print(){cout << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a = 10;class B{private:int _x;double _y;};
};
//匿名对象
int main()
{A aa;aa.Print();//A aa(); //此时不确定是函数还是类cout << sizeof(aa) << endl;//计算的大小是4,并不包含B类return 0;
}

6.匿名对象

  1. 用类型(实参),这种对象叫做匿名对象;之前的那种是有名对象 类型 对象名(实参),是有名对象
  2. 匿名对象的生命周期只有一行,和编译器生成的临时对象一样;一般临时用一下,可以用匿名对象
#include <iostream>
using namespace std;
class A
{
public:void Print(){cout << _a << endl;}~A(){cout << "~A()" << endl;}
private:int _a = 10;
};int main()
{A aa;aa.Print();//A aa(); //此时不确定是函数还是类//匿名对象,和临时对象一样声明周期只有一行,A();//匿名对象,可以直接调用函数;对比上面要少写一行A().Print();return 0;
}

7.对象拷贝时的编译器优化

  1. 现在的编译器为了提高程序的效率,不影响正确性的情况下都会进行优化;尽可能减少传值和传返回值的过程可省略的部分
  2. 有像 构造临时对象 + 拷贝构造 优化成直接构造
  3. 至于怎么优化看各自的编译器,C++并没有严格的规定;当前主流的比较新的编译器会优化连续拷贝并进行合并优化,有些编译器会更加激进的合并优化
  4. 初始化对象时,强制类型转换也是根据构造函数来看的,是需要看构造函数的参数的
#include <iostream>
using namespace std;
class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 1)" << endl;}//拷贝构造A(const A& xx):_a(xx._a){cout << "A(const A & xx)" << endl;}~A(){cout << _a << "~A()" << endl;}void Print(){cout << _a << endl;}A& operator++(){_a+= 100;return *this;}A& operator=(const A& xx){cout << "A& operator=(const A& xx)" << endl;if (this != &xx)//不能和自己相同,否则就不对了{_a = xx._a;}return *this;}
private:int _a;
};void fun1(A aa)
{}//初始化对象时
//int main()
//{
//	A tmp = 1;// 构造一个临时对象 + 拷贝构造  都会转化成直接构造
//
//	const A& at = 10;//直接会强制类型转换,这个强制类型转换也是根据构造函数来看的
//	return 0;
//}//传参时的优化
//int main()
//{
//	A aa(1);
//	fun1(aa);//没有使用引用,会产生拷贝构造,出函数临时对象销毁
//
//	cout << endl;
//
//	//有优化
//	fun1(A(20));
//
//	cout << endl;
//
//	//有优化
//	fun1(30);//构造临时对象 + 拷贝构造 优化成直接构造
//	return 0;
//}//返回值
A fun2()
{A aa(1);++aa;cout << "------" << endl;return aa;//vs2022 优化比19版 更加激进;把aa的构造,拿101直接构造临时对象,并作为返回值
}//int main()
//{
//	fun2().Print();//使用函数的临时对象调用函数,并且临时对象的生命周期只在这一行
//	cout << "********" << endl;
//	return 0;
//}int main()
{A ret;ret = fun2();// 拿临时对象去赋值拷贝构造; 只优化了fun2()的拷贝构造ret.Print();cout << "**********" << endl << endl;return 0;
}

做好自己,减少竞争性的努力,走好自己的路,超越昨天的自己

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1550616.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌收录批量查询,如何批量查询谷歌收录以及提交网站进行收录的方法

在SEO优化过程中&#xff0c;了解并监控网站在谷歌搜索引擎中的收录情况至关重要。本文将详细介绍如何批量查询谷歌收录以及提交网站进行收录的方法&#xff0c;帮助网站管理员和SEO专家更有效地管理和优化网站。 一、谷歌收录批量查询方法 1.使用搜索引擎的site指令 …

前端考核总结

目录 JavaScript的基本数据类型有哪些&#xff1f;JavaScript中数据类型的检测方法JavaScript如何判断对象中的属性存在自身还是原型链上flex布局HTML5新标签Vue的基本概念Vue生命周期JavaScript中闭包的基本概念防抖节流双等号与三等号的区别显式转换 JavaScript的基本数据类型…

fastadmin搜索刷新列表,怎么限制用户频繁点击?

文章目录 fastadmin搜索刷新列表&#xff0c;怎么限制用户频繁点击&#xff1f;解决方案fastadmin事件方法实现完结 fastadmin搜索刷新列表&#xff0c;怎么限制用户频繁点击&#xff1f; fastadmin目前有个很致命的问题&#xff0c;就是用户可以频繁的点击搜索等按钮&#xf…

Qt --- 界面优化 --- QSS和绘图API

界面优化 》美化 一个程序的界面是否好看&#xff0c;是否重要呢。 有些面向专业领域的程序&#xff0c;界面好看与否&#xff0c;不是看关键&#xff0c;更关键的是实际的效果。有些面向普通用户领域的程序&#xff0c;界面好看&#xff0c;还是很大的加分项。 界面优化 Qt…

奖金高达 110 万元,Spatial Joy 2024 全球 AR 应用开发大赛启动

今年是AR应用开发大赛第三届&#xff0c;恰逢Rokid成立十周年&#xff0c;我们推出全新的大赛品牌“Spatial Joy”&#xff0c;引领开发者享受开发乐趣&#xff0c;为其打造充满挑战和惊喜的开发之旅&#xff0c;逐渐成为空间计算时代全球最大AR应用开发大赛。回顾大赛发展&…

PCB敷铜敷不了相同网络的线怎么办?

图片上的情况就是今天需要讲的内容&#xff0c;可以看出出来的线头是GND,敷的铜也是GND但是相同网络就是不能连在一起。 解释&#xff1a; 这是因为我们敷铜的时候属性选的是连接相同的net,如图所示&#xff1a; 解决办法&#xff1a; 只需要设置改为相同的Object就可以了&…

STM32+ADC+扫描模式

1 ADC简介 1 ADC(模拟到数字量的桥梁) 2 DAC(数字量到模拟的桥梁)&#xff0c;例如&#xff1a;PWM&#xff08;只有完全导通和断开的状态&#xff0c;无功率损耗的状态&#xff09; DAC主要用于波形生成&#xff08;信号发生器和音频解码器&#xff09; 3 模拟看门狗自动监…

高效的视频压缩标准H.264介绍,以及H.264在视频监控系统中的应用

目录 一、概述 二、 工作原理 三、技术特点与优势 1、高效压缩率 2、高质量视频 3、错误恢复能力 4、灵活性 四、编解码过程 1、编码过程 2、解码过程 五、帧类型与结构 1、I帧 2、P帧 3、B帧 六、应用与优势 1、节省存储空间和带宽 2、提高视频质量 3、适应…

2024大二上js高级+ES6学习9.29(深/浅拷贝,正则表达式,let/const,解构赋值,箭头函数,剩余参数)

9.29.2024 1.浅拷贝和深拷贝 Es6的语法糖&#xff1a;用assign将obj对象浅拷贝给o对象。 把数组写在前面是因为数组也是对象 2.正则表达式 创建和检测正则表达式 正则表达式的使用直接跳过&#xff0c;等要用时现查现用 3.ES6 4.let关键字 块级作用域是指在一个{}l里 变量提…

File 和 Blob两个对象有什么不同

Blob 在 JavaScript 中&#xff0c;Blob&#xff08;Binary Large Object&#xff09;对象用于表示不可变的、原始的二进制数据。它可以用来存储文件、图片、音频、视频、甚至是纯文本等各种类型的数据。Blob 提供了一种高效的方式来操作数据文件&#xff0c;而不需要将数据全…

招联金融内推-2025校招

【投递方式】 直接扫下方二维码&#xff0c;或点击内推官网https://wecruit.hotjob.cn/SU61025e262f9d247b98e0a2c2/mc/position/campus&#xff0c;使用内推码 igcefb 投递&#xff09; 【招聘岗位】 后台开发 前端开发 数据开发 数据运营 算法开发 技术运维 软件测试 产品策…

【springboot】使用thymeleaf模板

1. 导入依赖 首先&#xff0c;创建一个Spring Boot项目&#xff0c;并添加Thymeleaf依赖。在pom.xml文件中添加以下依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifa…

组合逻辑元件与时序逻辑元件

组合逻辑元件和时序逻辑元件都是数字电路中的基本构建块&#xff0c;但它们在功能和结构上存在显著差异。 1. 组合逻辑元件: 内容: 组合逻辑元件的输出仅取决于当前的输入&#xff0c;而与之前的输入无关。 它们没有记忆功能。 常见的组合逻辑元件包括&#xff1a; 与门 (AND…

美图AI短片创作工具MOKI全面开放 支持生成配乐、细节修改

人工智能 - Ai工具集 - 集合全球ai人工智能软件的工具箱网站 美图公司近日宣布&#xff0c;其研发的AI短片创作工具MOKI已正式向所有用户开放。这款专注于AI短片创作的工具&#xff0c;提供了包括动画短片、网文短剧等多种类型视频内容的生成能力&#xff0c;致力于为用户带来…

文件防泄密措施有哪些?6个方法有效防止文件泄密

想象一下&#xff0c;一群穿着黑衣的神秘人在电影中潜入高保安办公室&#xff0c;绕过各种高科技安保装置&#xff0c;只为偷走里面存放的饱含机密的文件&#xff01; 听起来是不是很刺激&#xff1f; 但如果这种情况发生在现实中&#xff0c;而且发生在你的企业或个人数据上…

【中级通信工程师】综合能力:2024年真题回顾(附答案)

【零基础3天通关中级通信工程师】 综合能力&#xff1a;2024年真题回顾 本文是根据参加考试的回忆并且结合网上几版资料复原的2024年通信考试中级《综合能力》的真题考卷&#xff0c;旨在为广大考生提供复习和备考的参考&#xff0c;试卷大体和真题相符&#xff0c;部分选项回…

互联网全景消息(6)之RocketMq-NameServer源码分析

一、RocketMQ介绍 RocketMQ 是阿里巴巴集团基于高可用分布式集群技术,自主研发的云正式商用的专业消息中间件,既可为分布式应用系统提供异步解耦和削峰填谷的能力,同时也具备互联网应用所需的海量消息堆积、高吞吐、可靠重试等特性,是阿里巴巴双 11 使用的核心产品。 二、…

[Linux]:线程(二)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 与Windows环境不同&#xff0c;我们在linux环境下需要通过指令进行各操作&…

MAC的几个常见的快捷方式

1.mac 查看图片好的方式 默认查看图片的方式无法直接切换上一张下一张 解决方法&#xff1a; 1.&#xff08;最好的方法&#xff09;选中图片直接按空格&#xff0c;进入快速预览图片 2.就是全部选中然后打开&#xff0c;但是说实话有点奇怪&#xff0c;而且很占内存 3.直接显示…

【JAVA开源】基于Vue和SpringBoot的网上租赁系统

本文项目编号 T 050 &#xff0c;文末自助获取源码 \color{red}{T050&#xff0c;文末自助获取源码} T050&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计5.4.1 用…