【C++ 初阶路】--- 类和对象(末)
目录
- 一、const成员
- 1.1 取地址及const取地址操作符重载
- 二、再谈构造函数
- 2.1 构造函数体赋值
- 2.2 初始化列表
- 2.3 explicit关键字
- 三、static成员
- 3.1 概念
- 3.2 特性
- 四、友元
- 4.1 友元函数
- 4.2 友元类
- 五、内部类
- 六、匿名对象
一、const成员
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

const对象不可以调用非const成员函数 -> 权限放大- 非
const对象可以调用const成员函数 -> 权限缩小 const成员函数内不可以调用其它的非const成员函数 ->this指针被const修饰,权限放大- 非
const成员函数内可以调用其它的const成员函数 -> 权限缩小
1.1 取地址及const取地址操作符重载
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
class Date
{
public:Date* operator&(){return this;}const Date* operator&() const{return this;}
private:int _year; // 年int _month; // 月int _day; // 日
};
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!
二、再谈构造函数
2.1 构造函数体赋值
在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。
2.2 初始化列表
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
Date(int year, int month, int day): _year(year), _month(month), _day(day)
{}
【注意】
- 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
- 类中包含以下成员,必须放在初始化列表位置进行初始化:
-
- 引用成员变量
-
- const成员变量
-
- 自定义类型成员(且该类没有默认构造函数时)
class A
{
public:A(int a):_a(a){}
private:int _a;
};
class B
{
public:B(int a, int ref):_aobj(a), _ref(ref), _n(10){}
private:A _aobj; // 没有默认构造函数int& _ref; // 引用const int _n; // const
};
有一些变量(引用,const)必须要在定义时初始化,对于一个类来说,在对象实列化时就整体定义了,那么哪里是每个成员定义的地方呢? 于是找到了对象实例化必须调用的构造函数,但如果在构造函数体中的话,可能出现多次初始化的情况。 最后规定了初始化列表这一概念!其是每个成员变量定义初始化的位置! 如上如所示
在构造函数体中的是赋值修改! 能用初始化列表就建议使用初始化列表
-
尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化(即使初始化列表未给值,被初始化为随机值)。 我们前面讲的在声明时给缺省值,其实那个缺省值就是给初始化列表用的!
-
成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {std::cout << _a1 << " " << _a2 << std::endl;}
private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print();
}

2.3 explicit关键字
构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。
class C
{
public:C(int c = 0):_c(c){}
private:int _c;
};int main()
{C cc1(10);C cc2 = 2;const C& cc3 = 3; //3处return 0;
}
如上程序可以正常运行,正是因为单参数构造函数支持隐式类型转换! 此处用2构造了一个类C的临时对象,然后再拷贝构造cc2。即:用一个整形变量给C类型对象赋值,实际编译器背后会用2构造一个无名对象,最后用无名对象给cc2对象进行拷贝构造。
3处也是可以的,cc3引用3构造出来的临时对象,具有常性,需要const引用!
用法粗略演示,MyStack类中存放C类,如果要插入数据,就要先定义C类对象(C cc1(1)),然后再插入(st.Push(cc1))。这样的话就太麻烦了,我们便可用如上方法,合理运用隐式类型转换!
class MyStack
{
public:void Push(const C& c) { /* ... */ }
private:C cc;// ...
};
int main()
{MyStack st1;C cc1(1);st1.Push(cc1);st1.Push(2); //单参数构造函数支持隐式类型转换return 0;
}
虽然有多个参数,但是创建对象时后两个参数可以不传递,也具有类型转换作用,如下日期类:
Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
用explicit修饰构造函数,将会禁止构造函数的隐式转换。
三、static成员
3.1 概念
声明为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()
{std::cout << A::GetACount() << std::endl;A a1, a2;A a3(a1);std::cout << A::GetACount() << std::endl;
}
3.2 特性
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区;
- 静态成员变量必须在类外定义,定义时不添加
static关键字,类中只是声明; - 类静态成员即可用 类名
::静态成员 或者 对象.静态成员 来访问; - 静态成员函数没有隐藏的
this指针,不能访问任何非静态成员; - 静态成员也是类的成员,受
public、protected、private访问限定符的限制;
【问题】
- 静态成员函数可以调用非静态成员函数吗?
- 非静态成员函数可以调用类的静态成员函数吗?
四、友元
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元分为:友元函数和友元类
4.1 友元函数
问题:现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。 this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。
//若重载成类的成员函数: ostream& operator<<(const Date* this, ostream& _cout);
// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
ostream& operator<<(ostream& _cout)
{_cout << _year << "-" << _month << "-" << _day << endl;return _cout;
}
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
//类中声明:
friend ostream& operator<<(ostream& _cout, const Date& d);//类外定义:
ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}
说明:
- 友元函数可访问类的私有和保护成员,但不是类的成员函数;
- 友元函数不能用const修饰(因为
const修饰的是隐藏的this,而友元函数没有隐藏的this指针); - 友元函数可以在类定义的任何地方声明,不受类访问限定符限制;
- 一个函数可以是多个类的友元函数;
- 友元函数的调用与普通函数的调用原理相同;
4.2 友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
- 友元关系是单向的,不具有交换性。
比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。 - 友元关系不能传递
如果C是B的友元, B是A的友元,则不能说明C时A的友元。 - 友元关系不能继承,在继承位置再给大家详细介绍。
class Time
{friend class Date; //声明日期类为时间类的友元类,则在日期类中直接访问Time类中的私有成员变量
public:Time(int hour = 0, int minute = 0, int second = 0):_hour(hour),_minute(minute),_second(second){}
private:int _hour;int _minute;int _second;
};class Date
{
public:Date(int year = 2024, int month = 6, int day = 26):_year(year),_month(month),_day(day){}void TimePrint(){//直接访问时间类私有的成员变量std::cout << _t._hour << ":" << _t._minute << ":" << _t._second << std::endl;}
private:int _year;int _month;int _day;Time _t;
};
五、内部类
概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。 内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类, 参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
特性:
- 内部类可以定义在外部类的
public、protected、private都是可以的。 - 注意内部类可以直接访问外部类中的
static成员,不需要外部类的对象/类名。 sizeof(外部类)=外部类,和内部类没有任何关系。
class A
{
public://B类受A类的类域限制class B{public:void func(const A& a){//B 天生就是 A 的友元, static成员直接访问std::cout << a._a << _c << std::endl;}private:int _b;};void fx(const B& b){//std::cout << b._b << std::endl; //不可访问,单向友元}
private:int _a;static int _c;
};
int _c = 10;int main()
{A::B b; //若 B 设为private,则不可访问std::cout << sizeof(A) << std::endl; // -> 4return 0;
}
六、匿名对象
我们前面讲过不能这么(A aa1();)定义对象,因为编译器无法识别是一个函数声明,还是对象定义。 但是我们可以这么(A();)定义匿名对象,匿名对象的特点不用取名字,但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数! 仿函数部分用的较多。

Date d;
d.Solution(10); //有名对象调用
Date().Solution(10); //匿名对象调用
相关文章:
【C++ 初阶路】--- 类和对象(末)
目录 一、const成员1.1 取地址及const取地址操作符重载 二、再谈构造函数2.1 构造函数体赋值2.2 初始化列表2.3 explicit关键字 三、static成员3.1 概念3.2 特性 四、友元4.1 友元函数4.2 友元类 五、内部类六、匿名对象 一、const成员 将const修饰的“成员函数”称之为const成…...
bable 【实用教程】
简介 bable 用于将 ES6 的语法编译为 ES5 只关心语法,不关心 API 是否正确。不处理模块化(webpack 会处理) 搭建开发环境 安装相关的包 npm i babel/cli babel/core babel/preset-env新建文件 .babelrc,内容为 { "presets…...
Android中使用startActivityForResult启动活动
Android中使用startActivityForResult启动活动 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!在本文中,我们将深入探讨Android开发中使用startActi…...
NineData和华为云在一起!提供一站式智能数据库DevOps平台
以GuassDB数据库为底座 NineData和华为云一起 为企业提供 一站式智能数据库DevOps平台 帮助开发者 高效、安全地完成 数据库SQL审核 访问控制、敏感数据保护等 日常数据库相关开发任务 NineData 智能数据管理平台 NineData 作为新一代的云原生智能数据管理平台…...
深入解析 Redisson分布式锁看门狗机制
一、Redisson分布式锁概述 1.1 分布式锁的意义 在分布式系统中,多个节点可能同时访问共享资源,导致数据不一致或竞态条件。分布式锁通过协调不同节点对共享资源的访问,确保数据的一致性和并发访问的安全性。 1.2 Redisson分布式锁的优势 …...
Apache Arrow 和数据的未来:开放标准推动人工智能发展
Apache Arrow 是一种开源列式内存格式,适用于平面数据和分层数据。在现代数据湖中,开放数据格式(如 Apache Arrow)位于现代对象存储的存储层中。这些格式成为对象存储中的对象。 在最新版本中,Apache Arrow 宣布计划从…...
Vue项目生产环境的打包优化
Vue项目生产环境的打包优化 前言 在这篇文章我们讨论Vue项目生产环境的打包优化,并按步骤展示实际优化过程中的修改和前后对比。 背景 刚开始的打包体积为48.71M 优化 步骤一:删除viser-vue viser-vue底层依赖antv/g2等库一并被删除,…...
oracle数据库之使用Java程序调用存储过程(二十四)
在Oracle数据库中,你可以使用Java程序来调用存储过程。这通常涉及几个步骤:首先,确保你的Java环境能够连接到Oracle数据库;其次,使用JDBC(Java Database Connectivity)来调用存储过程。 以下是…...
西电953总分第一、专业课第一考研上岸
今年上岸西电杭研院网信院网络与信息安全专业,总分370分,专业课116分,分别是总分第一名,专业课第一名,感谢研梦的953叶学姐,非常负责,本硕大佬学姐,当年密码学38分选手(满…...
pytorch-模型训练
目录 1. 模型训练的基本步骤1.1 train、test数据下载1.2 train、test数据加载1.3 Lenet5实例化、初始化loss函数、初始化优化器1.4 开始train和test 2. 完整代码 1. 模型训练的基本步骤 以cifar10和Lenet5为例 1.1 train、test数据下载 使用torchvision中的datasets可以方便…...
Linux /proc目录总结
1、概念 在Linux系统中,/proc目录是一个特殊的文件系统,通常被称为"proc文件系统"或"procfs"。这个文件系统以文件系统的方式为内核与进程之间的通信提供了一个接口。/proc目录中的文件大多数都提供了关于系统状态的信息࿰…...
【JavaEE】浅谈线程(二)
线程 线程的常见属性 线程属性可以通过下面的表格查看。 •ID 是线程的唯⼀标识,不同线程不会重复 • 名称是各种调试⼯具⽤到(如jconsoloe) • 状态表示线程当前所处的⼀个情况,下⾯我们会进⼀步说明 • 优先级高的线程理论上来…...
爬虫:爬取知乎热榜一级评论及回答2024不包含翻页
一、先上结果(注:本文仅为兴趣爱好探究,请勿进行商业利用或非法研究,负责后果自负,与作者无关) 1、爬标题及其具体内容 2、抓标题下的对应回答 3、爬取对应一级评论 二、上流程 1、获取cookies(相信哥哥姐姐…...
AI 编程探索- iOS动态标签控件
需求分析: 标签根据文字长度,自适应标签居中显示扩展 超过内容显示范围,需要换行显示,且保持居中显示 AI实现过程 提问: 回答: import UIKit import SnapKitclass DynamicLabelsContainerView: UIView…...
计算机网络——数据链路层(数据链路层概述及基本问题)
链路、数据链路和帧的概念 数据链路层在物理层提供服务的基础上向网络层提供服务,其主要作用是加强物理层传输原始比特流的功能,将物理层提供的可能出错的物理连接改造为逻辑上无差错的数据链路,使之对网络层表现为一条无差错的链路。 链路(…...
【前端】前端权限管理的实现方式:基于Vue项目的详细指南
前端权限管理的实现方式:基于Vue项目的详细指南 在Web开发中,前端权限管理是一个确保应用安全性和优化用户体验的关键部分。本文将详细介绍前端权限管理的几种实现方式,并通过Vue项目中的代码示例来演示具体实现方法。 前端权限管理的基本实…...
MySQL数据库基础练习系列——教务管理系统
项目名称与项目简介 教务管理系统是一个旨在帮助学校或教育机构管理教务活动的软件系统。它涵盖了学生信息管理、教师信息管理、课程管理、成绩管理以及相关的报表生成等功能。通过该系统,学校可以更加高效地处理教务数据,提升教学质量和管理水平。 1.…...
windowns server2016服务器配置php调用powerpoint COM组件
解决问题:windowns server2016服务器配置php调用powerpoint COM组件 环境: windows server2016 宝塔(nginxmysqlphp7.2) IIS 搭建宝塔: 下载地址:https://www.bt.cn/download/windows.html 安装使用&…...
Git之checkout/reset --hard/clean -f区别(四十二)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...
MySQL数据库基础练习系列:科研项目管理系统
DDL CREATE TABLE Users (user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT 用户ID,username VARCHAR(50) NOT NULL UNIQUE COMMENT 用户名,password VARCHAR(255) NOT NULL COMMENT 密码,gender ENUM(男, 女) NOT NULL COMMENT 性别,email VARCHAR(100) UNIQUE COMMENT 邮箱 …...
丢失MSCOMCTL.OCX组件无法打开程序 教你免费修复方法
在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…...
Qwen Pixel Art保姆级教学:Windows/Mac/Linux三平台Docker部署全流程
Qwen Pixel Art保姆级教学:Windows/Mac/Linux三平台Docker部署全流程 1. 准备工作 在开始部署前,请确保您的系统满足以下要求: 操作系统:Windows 10/11、macOS 10.15 或主流Linux发行版Docker环境:已安装Docker Des…...
NotaGen问题解决:生成速度慢怎么办?3个优化技巧提升效率
NotaGen问题解决:生成速度慢怎么办?3个优化技巧提升效率 1. 问题背景与诊断 1.1 NotaGen生成速度现状 NotaGen作为基于LLM的古典音乐生成系统,在创作高质量符号化音乐方面表现出色,但许多用户反馈生成一首完整的古典音乐作品通…...
vue-qrcode-reader进阶指南:如何提升图片识别二维码的成功率(含iOS兼容方案)
Vue-Qrcode-Reader实战进阶:图片识别优化与iOS兼容全方案 每次遇到用户举着手机抱怨"扫不出来"时,作为开发者都恨不得自己变成二维码。别急,经过三个月的真实项目打磨和上百次测试,我总结出这套提升vue-qrcode-reader识…...
SDXL 1.0电影级绘图工坊案例展示:用‘水墨山水+AI芯片’生成新国潮科技海报
SDXL 1.0电影级绘图工坊案例展示:用‘水墨山水AI芯片’生成新国潮科技海报 1. 引言:当传统水墨遇见未来科技 想象一下,一幅融合了东方水墨意境的山水画,画中不是传统的亭台楼阁,而是充满未来感的AI芯片与电路纹理。这…...
图图的嗨丝造相-Z-Image-Turbo效果展示:多肤色多发型渔网袜人像矩阵惊艳出炉
图图的嗨丝造相-Z-Image-Turbo效果展示:多肤色多发型渔网袜人像矩阵惊艳出炉 1. 模型效果惊艳亮相 今天我要向大家展示一个令人眼前一亮的AI图像生成模型——图图的嗨丝造相-Z-Image-Turbo。这个模型最特别的地方在于,它专门针对"大网渔网袜"…...
RGB-LED嵌入式驱动库:硬件抽象与PWM同步设计
1. RGB-LED库技术解析:面向嵌入式系统的全栈驱动设计1.1 库定位与工程价值rgb-led是一个面向Arduino生态但具备跨平台潜力的RGB LED控制库。其核心价值不在于提供炫酷动画效果,而在于构建一套硬件抽象层完备、时序可控、资源占用可预测的底层驱动框架。在…...
扫地机器人福音:LingBot-Depth快速部署,低成本实现视觉避障
扫地机器人福音:LingBot-Depth快速部署,低成本实现视觉避障 1. 引言:低成本视觉避障的突破 想象一下,你正在开发一款扫地机器人,最头疼的问题是什么?十有八九是避障功能。传统方案要么依赖昂贵的激光雷达…...
电子科大计算机复试简历避坑指南:项目经历怎么写才能让导师眼前一亮?
电子科大计算机复试简历避坑指南:项目经历怎么写才能让导师眼前一亮? 在计算机专业的复试中,简历是导师了解你的第一扇窗口。很多同学误以为简历只是简单罗列经历,殊不知它其实是引导面试走向的战略工具。特别是对于项目经历相对薄…...
driftnet使用教程
driftnet 是一款专注于从网络流量中实时捕获并提取图像(及音频)的工具,广泛应用于网络安全分析、流量监控和教学演示场景。其核心原理是监听指定网络接口的数据包,解析 HTTP 等协议传输的图像数据(如 JPG、PNG、GIF 等…...
