当前位置: 首页 > news >正文

C++类与对象(下)【详析】

类与对象(下)

目录

  • 类与对象(下)
    • 一、再谈构造函数
      • 1.构造函数体赋值
      • 2.初始化列表
        • 定义:
        • 注意点:
        • 总结:
      • 3.explicit关键字
        • 引入:
        • explicit:
    • 二、 static成员
        • 回顾:static作用
        • 引入:面试题
        • 特征:
    • 三、友元
    • 四、内部类(了解)
    • 五、匿名对象
        • 引入:
        • 作用:
    • 六、拷贝对象时的一些编译器优化
    • 再次理解面向对象

一、再谈构造函数

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.初始化列表

定义:

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

特点:

①每个成员变量都要走初始化列表,就算不显示写初始化列表,也会走初始化列表;

②如果不显示写初始化列表,声明处给了缺省值就会使用缺省值初始化,如果显示写了初始化列表,即使给了缺省值也不会使用

步骤如下:

1.对于内置类型,优先使用初始化列表;没显示写初始化列表,有缺省值用缺省值,没有就用随机值;

2.自定义类型,调用它的默认构造函数,如果没有默认构造就报错。


那么,对于我们熟知的Date类,其初始化列表如下:

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

注意点:

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

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

  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)

其实对于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 
};

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

分析过程如下:

image-20230301205801969

总结:

1、尽量使用初始化列表初始化;
2、一个类尽量提供默认构造(推荐提供全缺省);

3.explicit关键字

引入:

构造函数不仅可以构造与初始化对象, 对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用

// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用Date(int year):_year(year){}
// 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具有类型转换作用Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
void Test()
{//隐式类型的转换int i=0;double d=i;const double& rd=i;//单参数构造函数Date d1(2022);Date d2=2022;const Date& d5=2022;//拷贝构造Date d3(d1);Date d4=d1;
}    

这里发生了隐式类型的转换:从int类转换为了Date类,会涉及到中间开辟一个临时对象/变量,再会用这个临时对象来拷贝构造它(通常编译器优化后即为直接构造了)

若不想发生类型转换,即可使用explicit关键字

explicit:

explicit修饰构造函数,将会禁止构造函数的隐式转换:

image-20230302094850225


若是多参数构造,C++11支持,即:

Date d1={2023,3,1};
//等价于:
Date d2(2023,3,1);

注意,这里的等价于只是说明它们的功能结果相同,而实际意义却不同:第一种方式即为多参隐式构造,而第二种方式是直接构造

二、 static成员

回顾:static作用

1、在函数体内,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变(维持着上次函数调用后的值,而不是每次函数调用后,值都重新进行声明)

2、在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其他函数访问。它是一个本地的全局变量

3、在模块内,一个被声明为静态的函数只可被这一模块内的其他函数调用。也就是,这个函数被限制在声明它的模块的本地范围内使用

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

引入:面试题

【面试题】实现一个类计算程序中创建出了多少个类对象

class A
{
public://构造函数A(){++_count;}//拷贝构造A(A& _a){++_count;}//析构函数~A(){++_count;}//定义静态变量_countstatic int GetCount(){return _count;}
private:static int _count;
};
//在类外声明静态成员变量,并给予初始化
int A::_count = 0;  //静态成员变量定义初始化void test()
{cout << A::GetCount() << endl;A a1;A a2;A a3;cout << A::GetCount() << endl;
}

首先,这里可以用全局变量来实现我们的目标要求:

image-20230302193653734

那为何我们要把它设为static呢?原因是全局变量容易被更改,不安全!

特征:

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

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

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

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

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

因此由于static具有如上特性,它的定义方法如下:

image-20230302194106150

可以注意到,首先在类外定义,不加static关键字;在类中声明变量,由于它由private限定,因此我们再提供它的Get方法;而在使用时:

image-20230302194253119

我们用get方法得到它的值,再用类名::静态成员的方式对它进行访问,用于输出它的值


【问题一】静态成员函数可以调用非静态成员函数吗?

静态成员函数没有隐含的this指针,不能访问任何非静态成员,并且静态成员函数属于类而不是某个对象。

【问题二】非静态成员函数可以调用类的静态成员函数吗?

非静态成员函数可以调用类的静态成员函数。

三、友元

友元提供了一种突破封装的方式,有时提供了便利;但是友元会增加耦合度,破坏了封装,所以友元不宜多用

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

例如,在“面向对象(中)”我们写到的流插入和流提取就用到了友元函数:

//友元声明(类中的任意位置)friend inline ostream& operator<<(ostream& out, const Date& d);friend inline istream& operator>>(istream& in, Date& d);
// 流插入的重载
inline ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}// 流提取的重载
inline istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}

说明:

友元函数:

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

友元函数不能用const修饰

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

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

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

友元类:

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

友元关系是单向的,不具有交换性;比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接 访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

友元关系不能传递:如果C是B的友元, B是A的友元,则不能说明C时A的友元

友元关系不能继承,在继承位置再给大家详细介绍

四、内部类(了解)

所谓内部类,即是类中嵌套了类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元

例如:

class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void func(const A& a){cout << k << endl;   //OKcout << a.h << endl; //OK}};
};
int A::k = 1;       //B天生是A的友元体现
int main()
{cout << sizeof(A) << endl;A aa;A::B bb;        //指定域才能访问
}

image-20230302201332747


五、匿名对象

引入:

我们构造一个类的对象,通常有多种方式:

对于以下类:

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
class Solution {
public:int Sum_Solution(int n) {//...return n;}
};

定义对象有以下方式:

int main()
{A aa1;          //有名对象A();            //匿名对象A aa2(2);       //有名对象A aa3 = 2;      //有名对象return 0;
}

注意:不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义;

A aa1();

但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数

image-20230302204736500


作用:

那么匿名对象有什么作用呢?

// 匿名对象在这样场景下就很好用,当然还有一些其他使用场景;
Solution().Sum_Solution(10);

正常应该是:

Solution so;
so.Sum_Solution(10);

这里我们采用创建匿名对象调用函数

六、拷贝对象时的一些编译器优化

在传值和传返回值的过程中,一般C++编译器会做一些优化,减少对象的拷贝,这个在一些场景下是非常有用的

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A(){cout << "~A()" << endl;}
private:int _a;
};
void f1(A aa)
{}
A f2()
{A aa;return aa;
}
int main()
{// 传值传参A aa1;f1(aa1);cout << endl;// 传值返回f2();cout << endl;// 隐式类型,连续构造+拷贝构造->优化为直接构造f1(1);// 一个表达式中,连续构造+拷贝构造->优化为一个构造f1(A(2));cout << endl;// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造A aa2 = f2();cout << endl;// 一个表达式中,连续拷贝构造+赋值重载->无法优化aa1 = f2();cout << endl;return 0;
}

【场景一】

一个表达式中,连续构造+拷贝构造,编译器会优化为一个构造

【场景二】
一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造

【场景三】
一个表达式中,连续拷贝构造+赋值重载->无法优化。

再次理解面向对象

对现实世界的映射!——描述世界

image-20230303140942165

相关文章:

C++类与对象(下)【详析】

类与对象&#xff08;下&#xff09; 目录类与对象&#xff08;下&#xff09;一、再谈构造函数1.构造函数体赋值2.初始化列表定义&#xff1a;注意点&#xff1a;总结&#xff1a;3.explicit关键字引入&#xff1a;explicit&#xff1a;二、 static成员回顾&#xff1a;static…...

exe反编译为.py文件

介绍公司以前的一个exe包&#xff0c;我们需要查看里面python源码&#xff0c;但是以前的py源码文件找不到&#xff0c;所以只能反编译&#xff0c;介绍一下反编译的过程。首先准备&#xff1a;pyinstxtractor.py这个文件&#xff0c;网上很多&#xff0c;自己下载准备查看二进…...

38 openEuler搭建FTP服务器-FTP总体介绍

文章目录38 openEuler搭建FTP服务器-FTP总体介绍38.1 FTP简介38.2 FTP使用到的端口38.3 vsftpd简介38 openEuler搭建FTP服务器-FTP总体介绍 38.1 FTP简介 FTP&#xff08;File Transfer Protocol&#xff09;即文件传输协议&#xff0c;是互联网最早的传输协议之一&#xff0…...

三天吃透操作系统面试八股文

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…...

vue后台管理系统——添加i18n国际化功能——技能提升

昨天在写后台管理系统时&#xff0c;遇到一个需求就是需要实现国际化功能。 antd和element-ui这两个框架其实都是有国际化的。 具体展示形式就是如下&#xff1a; 点击右上角头部的语言&#xff0c;切换语言&#xff0c;然后整个系统的文字都改变成对应的语言展示。 切换成…...

理清gcc、g++、libc、glibc、libstdc++的关系

0 理清gcc、g++、libc、glibc、libstdc++的关系 0.1 $ dpkg -L libc6 $ dpkg -L libc6 /lib/x86_64-linux-gnu /lib/x86_64-linux-gnu/ld-2.31.so /lib/x86_64-linux-gnu/libBrokenLocale-2.31.so /lib/x86_64-linux-gnu/libSegFault.so /lib/x86_64-linux-gnu/libanl-2.31.s…...

一、快速入门 MongoDB 数据库

文章目录一、NoSQL 是什么1.1 NoSQL 简史1.2 NoSQL 的种类及其特性1.3 NoSQL 特点1.4 NoSQL 的优缺点1.5 NoSQL 与 SQL 数据库的比较二、MongoDB 基础知识2.1 MongoDB 是什么2.2 MongoDB 的体系结构2.3 MongoDB 的特点2.4 MongoDB 键特性2.5 MongoDB 的核心服务和工具2.6 Mongo…...

PMP第一章到第三章重要知识点

第1章引论 1.1指南概述和目的 PMBOK指南收录项目管理知识体系中被普遍认可为“良好实践”的那一部分&#xff1a; “普遍认可”&#xff1a;大多数时候适用于大多数项目&#xff0c;获得一致认可。 “良好实践”&#xff1a;能提高很多项目成功的可能性。 全球项目管理业界…...

【事务与锁】当Transactional遇上synchronized

事务与锁 - Transactional与Synchronize&#x1f970;前言问题回放问题一1、代码与结果复现2、原因分析3、解决方法问题二1、问题复现2、原因分析事务Transactional与锁synchronized1、synchronized与Transactional区别2、可能带来的问题3、针对问题二的解决前言 最近工作中遇…...

Pytorch模型转TensorRT步骤

Pytorch模型转TensorRT步骤 yolov5转TRT 流程 当前项目基于yolov5-6.0版本&#xff0c;如果使用其他版本代码请参考 https://github.com/wang-xinyu/tensorrtx/tree/master/yolov5 获取转换项目&#xff1a; git clone https://github.com/wang-xinyu/tensorrtx.git git …...

产品经理入门——必备技能之【产品运营】

文章目录一、基础介绍1.1 用户生命周期 & 产品生命周期1.2 运营的目的1.3 运营的阶段1.4 运营的主要工作&#xff08;海盗模型&#xff09;二、AARRR模型2.1 Acquisition 拉新2.2 Activision 促活2.3 Retention 留存2.4 Revenue 转化2.5 Referral 传播总结产品运营技能是产…...

【Java实现文件上传】java后端+vue前端实现文件上传全过程详解(附源码)

【写在前面】其实这篇文章我早就想写了&#xff0c;只是一直被需求开发耽搁&#xff0c;这不晚上刚好下班后有点时间&#xff0c;记录一下。需求是excel表格的上传&#xff0c;这个是很多业务系统不可或缺的功能点&#xff0c;再此也希望您能够读完我这篇文章对文件上传不再困惑…...

什么是SSD?SSD简述

什么是SSD&#xff1f;SSD简述前言一. SSD组成二. SSD存储介质存储介质按材料不同可分为三大类&#xff1a;光学存储介质、半导体存储介质和磁性存储介质三. SSD接口形态固态硬盘有SATA 3.0接口、MSATA接口、M.2接口、PCI-E接口、U.2接口五种类型。三. SSD闪存颗粒分类闪存颗粒…...

MySQL基础------sql指令1.0(查询操作->select)

目录 前言&#xff1a; 单表查询 1.查询当前所在数据库 2.查询整个表数据 3.查询某字段 4.条件查询 5.单行处理函数&#xff08;聚合函数&#xff09; 6.查询时给字段取别名 7.模糊查询 8.查询结果去除重复项 9.排序&#xff08;升序和降序&#xff09; 10. 分组查询 1…...

Python数据分析处理报告--实训小案例

目录 1、实验一 1.1、题目总览 1.2、代码解析 2、实现二 2.1、题目总览 2.2、代码解析 3、实验三 3.1、题目总览 3.2、代码解析 4、实验四 3.1、题目总览 3.2、代码解析 哈喽~今天学习记录的是数据分析实训小案例。 就用这个案例来好好巩固一下 python 数据分析三…...

OpenCV入门(十二)快速学会OpenCV 11几何变换

OpenCV入门&#xff08;十二&#xff09;快速学会OpenCV 11几何变换1.图像平移2.图像旋转3.仿射变换4.图像缩放我们在处理图像时&#xff0c;往往会遇到需要对图像进行几何变换的问题。图像的几何变换是图像处理和图像分析的基础内容之一&#xff0c;不仅提供了产生某些图像的可…...

小菜鸟Python历险记:(第二集)

今天写的文章是记录我从零开始学习Python的全过程。Python基础语法学习&#xff1a;Python中的数值运算一共有7种&#xff0c;分别是加法&#xff08;&#xff09;、减法&#xff08;-&#xff09;、除法&#xff08;/&#xff09;得到的结果是一个浮点数、乘法&#xff08;*&a…...

ContentProvider程序之间数据的相互调用

1权限的获取和调用 权限分为普通权限和危险权限&#xff0c;除了日历信息&#xff0c;电话&#xff0c;通话记录&#xff0c;相机&#xff0c;通讯录&#xff0c;定位&#xff0c;麦克风&#xff0c;电话&#xff0c;传感器&#xff0c;界面识别&#xff08;Activity-Recognit…...

金三银四最近一次面试,被阿里P8测开虐惨了...

都说金三银四涨薪季&#xff0c;我是着急忙慌的准备简历——5年软件测试经验&#xff0c;可独立测试大型产品项目&#xff0c;熟悉项目测试流程...薪资要求&#xff1f;5年测试经验起码能要个20K吧 我加班肝了一页半简历&#xff0c;投出去一周&#xff0c;面试电话倒是不少&a…...

算法题——给定一个字符串 s ,请你找出其中不含有重复字符的最长子串 的长度

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长子串 的长度 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”&am…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...