C++初阶 | [四] 类和对象(下)

news2025/1/12 12:25:32

摘要:初始化列表,explicit关键字,匿名对象,static成员,友元,内部类,编译器优化

类是对某一类实体(对象)来进行描述的,描述该对象具有哪些属性、哪些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象。


1. 初始化列表

构造函数函数体内是对成员变量进行赋值,而不是初始化!

初始化列表:成员变量定义的地方

为什么规定初始化列表是所有成员变量定义的地方?

对于以下三类特殊的成员变量类型,初始化列表的存在是必要的:

  • const 成员变量—— const 变量必须在定义时初始化
  • 引用 —— 引用必须初始化
  • 自己没有默认构造函数自定义类型变量

warning:Initialization is not assignment. Initialization happens when a variable is given a value when it is created. Assignement obliterates an object's current value and replaces that value with a new one.

 Four different ways  to define an int variable named units_sold and initialize it to 0:

  • int units_sold = 0;
  • int units_sold = {0}; //list initialization (C++11)
  • int units_solc{ 0 }; //list initialization (C++11)
  • int units_sold(0);

——《C++ Primer》

Use

  1. 冒号开始,逗号分隔,初始化值/表达式 用括号括起来。示例如下。
  2. 成员变量走初始化列表的顺序为成员变量声明的顺序.(如下图,先用v2初始化v1,而v2还未初始化所存储的为随机值)
  3. C++规定初始化列表是每个成员变量定义的地方,每个成员变量会走初始化列表(所以成员变量的初始化尽量使用初始化列表),定义的时候不给初始值——即在初始化列表没有显式写的成员变量——未被初始化。
  4. 在初始化列表没写的成员变量,对于内置类型将不做处理——初始化值为随机值(但因编译器不同而异),对于自定义类型默认调用它自己的构造函数

sum.能用初始化列表就用初始化列表,但同时有些场景需要初始化列表和构造函数体混用。(根据具体的需求而异)

补充:C++11 支持在成员变量声明的时候给缺省值,这个缺省值是给初始化列表用的,如果初始化列表没有显式给初始值,就用缺省值作为初始化值。


2. explicit 关键字

  • C++98 支持单参数隐式类型转化

  • C++11 进一步支持多参数隐式类型转化

 在构造函数前加 explicit 使得不能进行隐式类型转换:(示例如下)

class B
{
public:
	explicit B(const int b1, const int b2)
	{
		_b1 = b1;
		_b2 = b2;
	}
	explicit B(const B& b)
	{
		_b1 = b._b1;
		_b2 = b._b2;
	}
private:
	int _b1;
	int _b2;
};

3. 匿名对象

  • 匿名对象:生命周期仅在改匿名对象定义的这一行。e.g.A(7);
  • 有名对象:生命周期在该作用域。e.g.A aa(7);

用途:

  1. 传参(如果单/多参数隐式类型转化被禁)
  2. 定义对象就是为了调用成员函数 → 就可以用匿名对象去调用
  3. ……(匿名对象的用途是十分广泛的)

const引用会延长匿名对象的生命周期

const引用其实使得匿名对象变成了有名对象:引用给了匿名对象别名,这个“别名”的生命周期即为被引用的匿名对象的生命周期。e.g.const A& ref = A();


4. static 成员

如果我们有如下两个需求:

  • 统计累计创建了多少个对象
  • 统计正在使用的对象还有多少个

统计累计创建的对象:首先,我们可以选择创建全局变量来统计。同时,因为创建对象会自动调用构造函数,所以我们在构造函数体内对这个用于统计的变量进行++操作,这样每次创建一个对象,就会调用并执行构造函数,每次执行都会累计对这个全局变量++。

统计正在使用的对象:对象销毁会自动调用析构函数,创建的对象 - 已经析构的对象 = 正在使用的对象。

int e = 0;//统计累计创建的对象
int now_e = 0;//统计仍在使用的对象

class A
{
public:
	A(const int a = 0)
	{
		++e;
		++now_e;
		_a = a;
	}
	~A()
	{
		--now_e;
	}
private:
	int _a;
};

问题:不够封装,全局变量可能会被随意修改,将造成需求之外的影响。 → “封装” → 将变量放入类中  →  私有变量无法访问 → static 成员

static 成员变量

static 成员变量的性质:

  1. 属于所有对象——即整个类,而不是某一个对象。
  2. 不能给缺省值。
  3. 不走初始化列表,初始化列表是某个对象的初始化,而 static 成员变量不属于某个对象。
  4. 位于静态区。

static 成员变量的声明与定义:类内声明,类外定义(静态成员变量一定要在类外进行初始化)

class A
{
private:
	static int m;//static成员变量声明
};//这样写A相当于空类

int A::m = 0;//static成员变量定义

访问 static 成员变量的两种情况下的方式:

  • 如果 static 成员变量是 public 的:①创建对象访问;②通过指针访问(这里的指针只是为了突破类域,而不会解引用,之前在类和对象上的this指针关于空指针的内容有详细解释);③直接访问。
    class A
    {
    public:
    	static int m;//static成员变量声明
    };//这样写A相当于空类
    
    int A::m = 0;//static成员变量定义
    
    int main()
    {
    	A aa;
    	aa.m;//①创建对象访问;
    
    	A* p = nullptr;
    	p->m;//②通过指针访问
    
    	A::m = 1;//③直接访问
    	return 0;
    }
    
  • 如果 static 成员变量是 非public 的:提供函数接口访问,这样可以使得 static 成员变量是只读不可修改的(引用返回可修改,这个根据需求自己控制),不同于public的情况。
    class A
    {
    public:
    	int GetM()
    	{
    		return m;
    	}
    private:
    	static int m;//static成员变量声明
    };
    
    int A::m = 0;//static成员变量定义
    
    int main()
    {
    	A aa;
    	cout << aa.GetM() << endl;
    	return 0;
    }

static 成员函数

static 成员函数的性质:

  1. 没有 this 指针,不能访问非静态成员变量
  2. 访问方式同 static 成员变量——突破类域即可访问 

5. 友元

  • 友元函数

特性:

  1. 可以访问类的 private 和protected 的成员,但友元函数不是类的成员函数。
  2. 不能用 const 修饰(因为不是成员函数更没有 this 指针,const 修饰的是 this 指针)。
  3. 可在类定义的任何地方声明,不受访问限定符限制。
  4. 一个函数可以是多个类的友元函数。
  5. 友元函数的调用同普通函数
class Date
{
	
friend ostream& operator<<(ostream& out, Date d);//友元函数声明

private:
	int _year;
	int _month;
	int _day;
};


ostream& operator<<(ostream& out, Date d)//函数定义
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

  • 友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。(如下代码,B类在A类友元声明之后,B类中的所有成员函数相当于在A类中都进行了友元声明——可以访问A类的非公有成员。注意:A类不可以访问B类的非公有成员。)

友元类的性质:

①单向性(如下,B可以访问A,但A不可以访问B);

②友元关系不传递(B是A的友元,A是C的友元,不能得出B是C的友元);

③不继承。

class A
{
	friend class B;

private:
	int _a;
};



class B
{
	void Print(A _aa)
	{
		cout<<_aa._a;
	}

	//A aa;//注意:这个只是声明,不开空间
};

6. 内部类

内部类:在类中再定义一个类。内部类受外部类的类域和访问限定符限制,此外内部类与外部类是两个独立的类。

使用场景:内部类可以应用于当你想定义一个类而仅在某个类中使用时。

注意:如上图,C不可以访问D的非公有成员, D在C类域之内又封装了一层,并且根据友元类的单向性也是如此。


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

此部分内容仅作了解,在之前旧版本的博客有较为详细的讲述,详细内容可参见本文:C++ -4- 类和对象(下)


END

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

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

相关文章

shell脚本之循环语句(for、while、untli)

循环语句&#xff1a; 一定要有跳出循环条件 循环条件&#xff1a; 1.已知循环的次数&#xff08;新来十个人&#xff0c;就要新建十个账号 2.未知循环的次数&#xff0c;但是要有跳出循环条件&#xff08;对象生气&#xff0c;要道歉到原谅为止&#xff09; for&#xff…

SpringBoot_websocket实战

SpringBoot_websocket实战 前言1.websocket入门1.1 websocket最小化配置1.1.1 后端配置1.1.2 前端配置 1.2 websocket使用sockjs1.2.1 后端配置1.2.2 前端配置 1.3 websocket使用stomp协议1.3.1 后端配置1.3.2 前端配置 2.websocket进阶2.1 websocket与stomp有什么区别2.2 webs…

【ThingJS】类型转换以及注册

前言 目前国家提倡加快数字化发展&#xff0c;建设数字中国&#xff0c;并于今年2月份中共中央、国务院印发的《数字中国建设整体布局规划》中明确&#xff0c;数字中国建设按照“2522”的整体框架进行布局。其中提到“构建以数字孪生流域为核心的智慧水利体系”&#xff0c;可…

HarmonyOS(三)—— 应用程序入口—UIAbility

前言 学习过android的同学都是知道Activity&#xff0c;Activity是Android组件中最基本也是最为常见用的四大组件之一&#xff0c;用户可以用来交互为了完成某项任务。 Activity中所有操作都与用户密切相关&#xff0c;是一个负责与用户交互的组件&#xff0c;可以通过setCon…

Mac自带的看图如何连续查看多张图片

一、问题 mac看访达里的图片时&#xff0c;双击打开一张图片&#xff0c;然后按上下左右键都没法切换到另外的图片。而且也没找到像window一样单击缩略图可以看到预览图。其实是自己不懂得怎么使用&#xff0c;哈哈哈&#x1f602; 二、方法 2.1、图标方式 可以看到缩略图&a…

原理Redis-QuickList

QuickList **问题1&#xff1a;**ZipList虽然节省内存&#xff0c;但申请内存必须是连续空间&#xff0c;如果内存占用较多&#xff0c;申请内存效率很低。怎么办&#xff1f; 为了缓解这个问题&#xff0c;我们必须限制ZipList的长度和entry大小。 **问题2&#xff1a;**但是…

【NLP】GPT 模型如何工作

介绍 2021 年&#xff0c;我使用 GPT 模型编写了最初的几行代码&#xff0c;那时我意识到文本生成已经达到了拐点。我要求 GPT-3 总结一份很长的文档&#xff0c;并尝试了几次提示。我可以看到结果比以前的模型先进得多&#xff0c;这让我对这项技术感到兴奋&#xff0c;并渴望…

[数据结构]-AVL树

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、AVL树基…

陪玩圈子系统APP小程序H5,详细介绍,源码交付,支持二开!

陪玩圈子系统&#xff0c;页面展示&#xff0c;源码交付&#xff0c;支持二开&#xff01; 陪玩后端下载地址&#xff1a;电竞开黑陪玩系统小程序&#xff0c;APP&#xff0c;H5: 本系统是集齐开黑&#xff0c;陪玩&#xff0c;陪聊于一体的专业APP&#xff0c;小程序&#xff…

Github Copilot AI编码完成工具

目录 一、GitHub Copilot 1、简介 2、工作原理 3、功能 二、GitHub Copilot X 1、什么是 GitHub Copilot X 2、GitHub Copilot X 的功能 三、支持、使用 1、支持 2、使用 四、实际研究、验证(代码方向) 1、代码生成 2、代码提示 3、生成测试用例 4、代码解释 5…

排序算法--归并排序

实现逻辑 ① 将序列每相邻两个数字进行归并操作&#xff0c;形成floor(n/2)个序列&#xff0c;排序后每个序列包含两个元素 ② 将上述序列再次归并&#xff0c;形成floor(n/4)个序列&#xff0c;每个序列包含四个元素 ③ 重复步骤②&#xff0c;直到所有元素排序完毕 void pri…

Rust并发编程:理解线程与并发

大家好&#xff01;我是lincyang。 今天我们来深入探讨Rust中的并发编程&#xff0c;特别是线程的使用和并发的基本概念。 Rust中的线程 Rust使用线程来实现并发。线程是操作系统可以同时运行的最小指令集。在Rust中&#xff0c;创建线程非常简单&#xff0c;但与此同时&…

SHAP - 机器学习模型可解释性工具

github地址&#xff1a;shap/docs/index.rst at master shap/shap (github.com) SHAP使用文档&#xff1a;欢迎使用 SHAP 文档 — SHAP 最新文档 SHAP介绍 SHAP&#xff08;SHapley Additive exPlanations&#xff09;是一种用于解释预测结果的方法&#xff0c;它基于Shapley…

ADB命令介绍

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

系列七、ThreadLocal为什么会导致内存泄漏

一、ThreadLocal为什么会导致内存泄露 1.1、ThreadLocalMap的基本结构 ThreadLocalMap是ThreadLocal的内部类&#xff0c;没有实现Map接口&#xff0c;用独立的方式实现了Map的功能&#xff0c;其内部的Entry也是独立实现的。源码如下&#xff1a; 1.2、ThreadLocal引用示意图…

逸学java【初级菜鸟篇】9.3 Stream流

hi&#xff0c;我是逸尘&#xff0c;一起学java吧 得益于Lambda所带来的函数式编程&#xff0c;引入了一个全新的Stream流概念&#xff08;就是都基本使用lambda的形式&#xff09;。 流处理 我们首先理解什么是流处理&#xff0c;它类似于sql语句&#xff0c;可以执行非常复…

cocos2dx ​​Animate3D(二)

Twirl 扭曲旋转特效 // 持续时间(时间过后不会回到原来的样子) // 整个屏幕被分成几行几列 // 扭曲中心位置 // 扭曲的数量 // 振幅 static Twirl* create(float duration, const Size& gridSize, const Vec2& position, unsigned int twirls, float amplitude)…

Python基础【二】--基本语句【2023.11.22】

1.条件语句 在进行逻辑判断时&#xff0c;我们需要用到条件语句&#xff0c;Python 提供了 if、elif、else 来进行逻辑判断。格式如下所示&#xff1a; if 判断条件1:执行语句1... elif 判断条件2:执行语句2... elif 判断条件3:执行语句3... else:执行语句4...ainput("请输…

Django 模型和Admin站点管理(三)

一、定义模型 &#xff08;1&#xff09; 创建模型类&#xff0c;必须要继承自 models.Model from django.db import models# Create your models here. #设计数据库 #创建模型 class UserModel(models.Model):namemodels.CharField(max_length30) #对应于SQL name varchar(30…

EMG肌肉信号处理合集 (一)

本文归纳了常见的肌肉信号预处理流程&#xff0c;方便EMG信号的后续分析。使用pyemgpipeline库 来进行信号的处理。文中使用了 UC Irvine 数据库的下肢数据。 目录 1 使用wrappers 定义数据类&#xff0c;来进行后续的操作 2 肌电信号DC偏置去除 3 带通滤波器处理 4 对肌电…