c++初阶------类和对象(下)

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


类和对象

  • **作者前言**
  • 类的构造函数
    • 初始化列表
  • static成员
    • 静态成员
    • 静态成员函数
  • explicit关键字
    • 单参数的隐式类型转换
    • 多参数类型的隐式类型转换(c++11后支持)
  • 友元
    • 友元函数
    • 友元类
  • 内部类
  • 扩展
    • 拷贝小误区
    • 构造优化(编译器的优化)

类的构造函数

前面我们学习了类的构造函数的定义,如下:
在这里插入图片描述
这个就是我们之前写的构造函数的定义,叫做函数体内初始化,除了这样定义,还有另外一种定义叫初始化列表

初始化列表

使用这个主要是为了解决一些类型无法初始化

  1. 类中的引用无法初始化
    在这里插入图片描述
    可以看到使用函数体内初始化引用时是无法初始化引用变量的,因为在类中的成员是声明,在函数内才是定义(创建对象),const 也要在定义时初始化,为了解决引用和const在类的成员函数里面初始化不了,就有了初始化列表,
    初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段
		Date()//初始化列表:_a(d1._a),_b(30){//函数体内定义_year = d1._year;_month = (d1._month);_day = (d1._day);}

这里是一个类的默认构造函数,

  1. 假设初始化列表没有写内置类型的定义和函数体内定义也没有,内置类型就是随机值(编译器定义的)
  2. 如果类的成员有自定义类型,没有在初始化列表定义,自定义类型会自动调用它本身的默认构造函数。
    无参的构造函数全缺省的构造函数以及编译器自己生成的都称为默认构造函数
    (不用传参的构造函数)
namespace naco
{class D{public://默认构造D(int a = 20){_a = 20;}private:int _a;};class Date{public:Date(int year, int month, int day)//初始化列表:_a(year), _b(30),A(20)//不想调用自己默认值默认构造,就传值{//函数体内定义_year = year;_month = (month);_day = (day);}~Date(){cout << _year << "-" << _month << "-" << _day << endl;}private://声明int _year;int _month;int _day;int& _a;const int _b;D A;};
}

我们还可以在声明的时候定义,这样就可以哪怕初始化列表不写,也不会报错

class Date{public:Date(int year, int month, int day)//初始化列表:_a(year),A(20){//函数体内定义_year = year;_month = (month);_day = (day);}~Date(){cout << _year << "-" << _month << "-" << _day << endl;}private://声明int _year;int _month;int _day;int& _a;const int _b = 100;D A;//自定义类型};

所以可以总结一下:
初始化列表主要针对三类

  1. 引用
  2. const修饰的变量
  3. 没有默认构造函数的自定义类型成员,有默认构造的对象,哪怕没有定义也会调用自己的默认构造,或者是不使用默认值的自定义类型成员

建议:

  1. 构造函数由初始化列表和函数体构成,缺一不可,
  2. 每个成员只能再初始化列表出现一次,但是不会影响函数体内初始化,在函数体内还可以出现
  3. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关建议类中声明次序和初始化顺序一样
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和随机值,先初始化_a2,然后再初始化_a1
,

static成员

静态成员

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化,
例子:
写出一个类,计算出一个程序中的类对象有多少个

class A
{
public:A(int a = 20){_a = a;++count;}A(const A& d1){_a = d1._a;++d1.count;}~A(){--count;}void Print(){cout << count << endl;}private://shngmstatic int count;//属于全部对象共同使用的.不会每个对象都有专属的count,而是全部对象公用这个countint _a;};
//静态成员定义
int A::count = 0;
int main()
{A a(10);A b(30);a.Print();return 0;
}

静态成员函数

  1. main函数之前就初始化了.而不是创建对象后才初始化,
  2. 只是放到类中,属于类的私有成员,
  3. 静态成员是全局的,所有对象共用,
  4. 静态成员只能在类外面定义,不属于类外访问,不能走构造函数的路
    静态成员访问形式:
A aa;
A::count;
aa.count;
//这两种都可以访问,

可能有些小可爱觉得不太方便,就会使用一下匿名对象,这个匿名对象和C语言的匿名结构体是不一样的,匿名对象的生命周期只是在一行中

class A
{
public:A(int a = 20){_a = a;++count;}A(const A& d1){_a = d1._a;++d1.count;}~A(){--count;}void Print(){cout << A::count << endl;}private://shngmstatic int count;int _a;};
//定义
int A::count = 0;
int main()
{A().Print();//A()是一个匿名对象,生命周期在这一行,出了这一行,这个匿名对象就会被析构return 0;
}

A()就是匿名对象,生命周期在定义的那一行中,

静态成员函数

特点:没有this指针
调用静态成员函数和调用静态成员的方法是一样的,

在这里插入图片描述
可以自定义类型::静态成员函数对象.静态成员函数调用

注意: 静态成员函数可以直接调用静态成员
作用

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
  6. 静态成员可以在类中直接使用,

explicit关键字

单参数的隐式类型转换

class A
{
public:A(int a = 20):_a(a){}A(const A& d1){_a = d1._a;}~A(){cout << _a << endl;}
private:int _a;
};
int main()
{A tes = 20;return 0;
}

上面代码涉及到了内置类型对象隐式转换成自定义类型对象
在这里插入图片描述
需要注意的是支持这个方式是要构造函数的参数只有一个int类型参数(this不包含在内),前面我们知道这个临时变量具有常性,需要用const修饰的变量来接收,
能隐式互相转的内置类型是整形(int)浮点数,这里两种对是类型相近的,表示数据的大小。

内置类型转自定义类型的话,前提是自定义类型的构造函数必须是单参数构造函数
还有就是全缺省构造函数。和只有一个参数没有默认值的半缺省构造函数,都可以隐式转化
简单的理解就是只能传一个参数的构造函数可以
在这里插入图片描述

多参数类型的隐式类型转换(c++11后支持)

上面是只能传一个参数的隐式转换,如果是多参数的话可以这样

class A
{
public:A(int a , int b = 20, int c=30):_a(a),_b(b),_c(c){}A(const A& d1){_a = d1._a;_b = d1._b;_c = d1._c;}~A(){cout << _a << endl;}
private:int _a;int _b;int _c;};
int main()
{A tes = {30, 20 ,10};const A& test = {60, 50, 10};//引用的是A(60,50,10)的临时变量return 0;
}

这里是要在c++11后才支持的,多参数的类型转换,一样的道理,

为了防止这些转换,cpp就有了一个explicit关键字

在这里插入图片描述
使用这个关键字来修饰构造函数就会防止有隐式转换了

友元

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

友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。定义在外面就不要friend,

class A
{
public:A(int a , int b = 20, int c=30):_a(a),_b(b),_c(c){}A(const A& d1){_a = d1._a;_b = d1._b;_c = d1._c;}~A(){cout << _a << endl;}//友元函数(不是任何类的成员函数)friend std::ostream& operator<<(std::ostream& out, const A& d1);private:int _a;int _b;int _c;
};
std::ostream& operator<<(std::ostream& out, const A& d1)
{out << d1._a << d1._b << d1._c;//访问了类的私有成员,没有this指针return out;
}

特征

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

  2. 友元函数不能用const修饰

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

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

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

友元类

class A
{public:friend class B;A(int a, int b = 20, int c = 30):_a(a), _b(b), _c(c){}A(const A& d1){_a = d1._a;_b = d1._b;_c = d1._c;}~A(){cout << _a << endl;}private:int _a;int _b;int _c;
};
class B
{
public:B(int a = 20, int b = 30, int c = 40, int Ba = 50, int Bb = 60, int Bc = 70):t(a,b,c),_Ba(Ba),_Bb(Bb),_Bc(Bc){}void Print(){cout << t._a << " " << t._b << " " << t._c << endl;//直接访问t的私有成员}~B(){cout << "B析构了" << endl;}private:int _Ba;int _Bb;int _Bc;A t;
};
int main()
{B te = 50;te.Print();return 0;
}

在这里插入图片描述
特征

  1. 友元关系是单向的,不具有交换性。(友元类可以访问普通类的私有成员或者成员函数,前提是普通类声明过这个友元类)
  2. 友元关系不能传递(C是B的友元类,B是A的友元类,但是C不是A的友元类)
  3. 友元关系不能继承

内部类

如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类
不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越
的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访
问外部类中的所有成员。但是外部类不是内部类的友元。
如果内部类被public,可以在类外面进行定义,需要使用 外部类名:: 内部类,否则的话只能在外部类内定义使用,

class A
{
public:A(int a, int b, int c):bb(20){_a = a;_b = b;_c = c;}
private:class B{public:B(int b){_bb = b;}~B(){A aa(30,40,50);aa._a++;aa._b++;aa._c++;}private:int _bb;};private:int _a;int _b;int _c;B bb;//内部类
};
int main()
{A aa(1,1,1);//A::B bb(1);//内部类被oublic可以使用return 0;
}

特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

扩展

拷贝小误区

class A
{
public:A(int a = 10){_a = a;}A(const A& d){_a = d._a;}
private:int _a;
};
int main()
{A a1;A a2 = a1;//拷贝A a3(20);a1 = a3;//赋值return 0;
}
  1. 一个存在的对象拷贝构造另一个要创建的对象,就是拷贝构造
  2. 两个存在的对象使用=就是赋值

构造优化(编译器的优化)

随着时代的变迁,编译器对于一些代码优化了很好,比如构造函数
同一个表达式中,连续的构造+构造/ 构造+拷贝构造/拷贝构造+拷贝构造合二为一

在这里插入图片描述
红框中的大概意思就是,用1构造一个临时对象,然后用这个临时对象拷贝构造a4,但是结果却是调用了构造函数,所以就会有一个结论:

构造 + 构造=>构造

拷贝构造+构造=>构造
在这里插入图片描述

拷贝构造 + 拷贝构造=>拷贝构造
在这里插入图片描述

不同的编译器优化成度不同,但是普遍有正常的优化,有一些编译器优化可能是多个表达式优化
比如VS2019:
在这里插入图片描述
Linux下的g++编译器
在这里插入图片描述
就可以看出差别,不同的编译器优化的程度会不同。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

马斯克将在本周,开源类ChatGPT产品Grok

3月11日晚&#xff0c;马斯克在社交平台宣布&#xff0c;将在本周开源生成式AI产品——Grok。 Grok是马斯克旗下公司xAI在去年11月发布的&#xff0c;一款类ChatGPT产品&#xff0c;可以提供生成文本、代码、邮件、信息检索等功能。其测试性能超过GPT-3.5、LLaMA 2 70B&#x…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的铁轨缺陷检测系统(Python+PySide6界面+训练代码)

摘要&#xff1a;开发铁轨缺陷检测系统对于物流行业、制造业具有重要作用。本篇博客详细介绍了如何运用深度学习构建一个铁轨缺陷检测系统&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&#xff0c;展示了不同模…

Linux运维:深入了解 Linux 目录结构

Linux运维&#xff1a;深入了解 Linux 目录结构 一、 Linux 目录结构与 Windows之间的主要区别二、Linux根目录结构三、常见目录及其作用 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 一、 Linux 目录结构与 Windows之间的主要区别 1、根…

vivado clock ip核的使用

clock 偶数倍分频就是进行计数器计数&#xff0c;奇数倍分频如果不要求占空比的话也是进行计数&#xff0c;如果要求0.5的占空比的话&#xff0c;则需要进行两个计数器&#xff0c; 对于实现占空比为50%的N倍奇数分频&#xff0c;我们可以分解为两个通道&#xff1a; 上升沿触…

数据拯救指南:解决文件或目录损坏且无法读取的终极策略

在日常的计算机使用中&#xff0c;我们经常会遇到文件或目录损坏且无法读取的困扰。当这类问题发生时&#xff0c;无论是重要的文档、照片还是视频文件&#xff0c;都可能会变得无法访问&#xff0c;给我们的工作和生活带来极大的不便。面对这种情况&#xff0c;我们首先需要了…

落地灯哪个牌子好?五款品质可靠的落地灯,各具亮点

近年来&#xff0c;落地灯作为最适合目前用眼人群使用的照明电器&#xff0c;以显著的照明效果获得了广泛认可&#xff0c;并成为众多学生党、上班族用眼时的必备工具。其受欢迎的程度不断攀升&#xff0c;促使越来越多的人都选择入手落地灯。然而&#xff0c;我发现市场上也有…

关于JSP的打印调试,再来一篇巩固巩固

JSP实质上就是html混入了Java&#xff0c;或者说是HTMLJavaScriptCSSJava的混合⽂件&#xff0c;那么就会牵扯到各种语言之间的变量引用问题&#xff0c;既然基础是html&#xff0c;那么就先看看html怎么引用其他内容&#xff0c;以及其他内容间值的互引用。 1、Html获取JavaS…

数据结构之栈详解(C语言手撕)

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…

HYBBS 表白墙网站PHP程序源码,支持封装成APP

PHP表白墙网站源码&#xff0c;适用于校园内或校区间使用&#xff0c;同时支持封装成APP。告别使用QQ空间的表白墙。 简单安装&#xff0c;只需PHP版本5.6以上即可。 通过上传程序进行安装&#xff0c;并设置账号密码&#xff0c;登录后台后切换模板&#xff0c;适配手机和PC…

如何在Linux本地搭建Tale网站并实现无公网ip远程访问

文章目录 前言1. Tale网站搭建1.1 检查本地环境1.2 部署Tale个人博客系统1.3 启动Tale服务1.4 访问博客地址 2. Linux安装Cpolar内网穿透3. 创建Tale博客公网地址4. 使用公网地址访问Tale 前言 今天给大家带来一款基于 Java 语言的轻量级博客开源项目——Tale&#xff0c;Tale…

JMeter 二次开发之环境准备

通过JMeter二次开发&#xff0c;可以充分发挥JMeter的潜力&#xff0c;定制化和扩展工具的能力以满足具体需求。无论是开发自定义插件、函数二次开发还是定制UI&#xff0c;深入学习和掌握JMeter的二次开发技术&#xff0c;将为接口功能测试/接口性能测试工作带来更多的便利和效…

【Linux/OS学习】基础文件控制/IO——内存文件

文章目录 一、 基础文件控制1.1 系统接口open函数1.2 Linux中文件描述符1.2 C语言FILE中的文件描述符 二、重定向1. 输出重定向2. 追加重定向3. 输入重定向 tips:fd的分配规则 一个文件要有一个唯一的文件标识&#xff0c;以便用户识别和引用。 文件名包含3部分&#xff1a;文件…

进电子厂了,感触颇多...

作者&#xff1a;三哥 个人网站&#xff1a;https://j3code.cn 本文已收录到语雀&#xff1a;https://www.yuque.com/j3code/me-public-note/lpgzm6y2nv9iw8ec 是的&#xff0c;真进电子厂了&#xff0c;但主人公不是我。 虽然我不是主人公&#xff0c;但是我经历的过程是和主…

jdk1.8下载与安装 图文版

JDK下载 首先在Oracle官网上下载jdk1.8.https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html,如下图所示&#xff0c;找到jdk1.8,选择对应的版本 或者 链接&#xff1a;https://pan.baidu.com/s/13lZy7JKE1xn-dXx_VG1QFA?pwd29wl 提取码&#xff1a;…

谷歌承认“窃取”OpenAI模型关键信息

什么&#xff1f;谷歌成功偷家OpenAI&#xff0c;还窃取到了gpt-3.5-turbo关键信息&#xff1f;&#xff1f;&#xff1f; 是的&#xff0c;你没看错。 根据谷歌自己的说法&#xff0c;它不仅还原了OpenAI大模型的整个投影矩阵&#xff08;projection matrix&#xff09;&…

Redis高可用之哨兵模式和集群模式

Redis高可用 Redis哨兵高可用 概述 sentinel哨兵是特殊的redis服务&#xff0c;不提供读写服务&#xff0c;主要用来监控redis实例节点。 哨兵架构下client端第一次从哨兵找出redis的主节点&#xff0c;后续就直接访问redis的主节点 不会每次都通过sentinel代理访问redis的主…

知识图谱技术综述

作者简介:徐增林(1980 − ),男,博士,教授,主要从事机器学习及其在社会网络分析、互联网、计算生物学、信息安全等方面的研究. 【摘要】 知识图谱技术是人工智能技术的重要组成部分,其建立的具有语义处理能力与开放互联能力的知识库,可在智能搜索、智能问答、个性化推…

TodoList案例——静态组件

Todo-List案例 组件化编码流程 1、实现静态组件&#xff1a;抽取组件&#xff0c;使用组件实现静态页面效果 2、展示动态数据&#xff1a; 2.1数据的类型、名称是什么&#xff1f; 2.2数据保存在哪个组件&#xff1f; 3、交互——从绑定事件监听开始 演示&#xff1a; App组…

九、软考-系统架构设计师笔记-软件可靠性基础知识

1、软件可靠性概念 软件可靠性定义 软件可靠性(Software Reliability)是软件产品在规定的条件下和规定的时间区间完成规定功能的能力。 规定的条件是指直接与软件运行相关的使用该软件的计算机系统的状态和软件的输入条件&#xff0c;或统称为软件运行时的外部输入条件。规定…

自反检索增强生成 (SELF-RAG)

理想情况下&#xff0c;生成式 AI 的落地应用需要提供真实且高质量的响应。SELF-RAG 正是为解决此问题而被创建的。 背景介绍 有趣的是&#xff0c;RAG的发展轨迹与提示工程&#xff08;prompt engineering&#xff09;非常相似。RAG 最初是一个简单而有效的概念&#xff0c;其…