当前位置: 首页 > 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…...

从BGA封装到Xtacking架构:图解NAND堆叠技术如何影响SSD性能

从BGA封装到Xtacking架构&#xff1a;NAND堆叠技术如何重塑SSD性能格局 当一块企业级SSD的读写速度突破7GB/s时&#xff0c;工程师们发现传统的NAND封装技术正在成为性能提升的瓶颈。在PCIe 5.0时代&#xff0c;信号传输速率需要达到2400MT/s才能充分发挥带宽潜力&#xff0c;而…...

FGA智能自动化:重新定义Fate/Grand Order效率提升新范式

FGA智能自动化&#xff1a;重新定义Fate/Grand Order效率提升新范式 【免费下载链接】FGA Auto-battle app for F/GO Android 项目地址: https://gitcode.com/gh_mirrors/fg/FGA 在Fate/Grand Order的游戏世界中&#xff0c;90%的玩家每天都在重复着机械的刷本操作&…...

golang如何实现零知识证明基础_golang零知识证明基础实现教程

Go 不内置零知识证明能力&#xff0c;需依赖第三方库&#xff1b;主流ZKP工具链绑定Rust/C/TS&#xff0c;Go生态缺乏生产级原生实现&#xff1b;crypto包仅提供基础原语&#xff0c;无法支撑ZKP所需多项式承诺、配对运算等高级密码操作。Go 本身不内置零知识证明&#xff08;Z…...

Windows下Gradle全局镜像配置避坑指南:从环境变量到init.gradle

Windows下Gradle全局镜像配置避坑指南&#xff1a;从环境变量到init.gradle 每次打开Android Studio准备大干一场时&#xff0c;那个卡在"Downloading gradle-xxx-all.zip"的进度条是不是让你想砸键盘&#xff1f;作为常年与Gradle斗智斗勇的老司机&#xff0c;今天我…...

Pixel Language Portal实操手册:自定义天空蓝主题(#e3f2fd)与金币黄按钮配置

Pixel Language Portal实操手册&#xff1a;自定义天空蓝主题(#e3f2fd)与金币黄按钮配置 1. 工具概览 **像素语言跨维传送门(Pixel Language Portal)**是一款基于腾讯Hunyuan-MT-7B核心引擎构建的创新翻译工具。与传统翻译软件不同&#xff0c;它将语言转换过程设计成一场16-…...

Python自动化测试框架入门教程

Python自动化测试框架入门教程&#xff1a;从零开始掌握Pytest和unittest &#x1f4dd; 摘要 自动化测试是现代软件开发不可或缺的一部分&#xff0c;能够显著提高代码质量和开发效率。本文将带你从零开始了解Python主流自动化测试框架——Pytest和unittest&#xff0c;包含…...

Pixel Aurora Engine真实作品:支持物理位移反馈的UI交互+生成图联动演示

Pixel Aurora Engine真实作品&#xff1a;支持物理位移反馈的UI交互生成图联动演示 1. 像素极光创意引擎介绍 Pixel Aurora Engine&#xff08;像素极光引擎&#xff09;是一款融合AI生成技术与复古游戏美学的创意工具。这款"虚拟游戏机"采用8-bit像素风格界面&…...

从零到一:阿里云天池街景符号识别Baseline实战指南

从零到一&#xff1a;阿里云天池街景符号识别Baseline实战指南 街景符号识别是计算机视觉领域一项极具挑战性的任务&#xff0c;它要求模型能够准确识别并理解街道场景中的各类符号信息。对于刚接触深度学习实战的开发者来说&#xff0c;如何从零开始构建一个完整的识别系统往往…...

RT thread—iic—at24c04读写操作

at24c04介绍&#xff1a;存储容量&#xff1a;4 Kbits&#xff08;即 512 字节&#xff09;。内部结构为 32 页&#xff0c;每页 16 字节。地址0x000-0x1FF通信接口&#xff1a;标准 I2C&#xff08;时钟线 SCL 和数据线 SDA&#xff09;&#xff0c;支持最高 400 kHz 的快速模…...

Exchange邮件批量删除工具有了网络版了

原有的<<Exchange邮件批量删除工具>>单机版现在已经更新为BS架构网络版&#xff0c;这样只要有网络就可以使用此系统了&#xff0c;方便随时应急。产品也启用了新名称为&#xff1a;MIRS邮件应急响应系统。此系统在几个有大型Exchange server部署的客户处使用效果很…...