超详解C++类与对象(下)

news2024/10/23 19:12:25

目录

1. 初始化列表 

1.1. 定义

2.2. 注意

2. 隐式类型转换

2.1. 内置类型

2.2. 自定义类型 

2.3. explicit关键字

 3.类的静态成员 

2.1. 定义

2.2. 注意

4.const成员函数

5. 友元 

5. 1友元函数

5.2. 友元类 

6. 内部类 

6.1. 定义

6.2. 注意

7. 匿名对象

7.1匿名对象

7.2延长生命周期的匿名对象 


💓 博客主页:C-SDN花园GGbond

⏩ 文章专栏:玩转c++

1. 初始化列表 

1.1. 定义

初始化列表作用与构造函数类似,它是在构造函数中以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。

下面我们还是以一个日期类来示范: 

class Date
{
public:
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{
	 //...
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d(2024,10,23);
	d.Print();
	return 0;
}

 

2.2. 注意
  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)。
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化:引用成员变量,const成员变量(const成员变量(也称为常量成员变量)需要在定义时进行初始化。这是因为const成员变量一旦被初始化之后,其值就不能被修改。因此,编译器需要确保在对象被创建时,这些常量成员变量就已经有了确定的初始值。),自定义类型成员(且该类没有默认构造函数时)。因为这些变量都需要在定义时初始化。
class A
{
public:
	A(int a)
		:_a(a)
	{}
private:
	int _a;
};
class B
{
public:
	B(int a, int ref)
		:_b(a)
		, _ref(ref)
		, _n(3)
	{}
private:
	A _b; // 没有默认构造函数
	int& _ref; // 引用
	const int _n; // const常量
};
  1. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

 

class A
{
public:
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}
	void Print() 
	{
		cout << _a1 << endl;
		cout << _a2 << endl;
	}
private:
	int _a2;
	int _a1;
};
int main()
{
	A aa(1);
	aa.Print();
}//输出??

 

 

2. 隐式类型转换

在学习C语言时我们就明白,当我们进行赋值时,如果赋值两边的类型不同时就可能发生隐式类型转换

2.1. 内置类型

在发生隐式类型转换时,如果都是内置类型就会先开辟一个临时变量,再将右操作数强制类型转换为左操作数的类型,最后用这个临时变量对左操作数进行赋值。注意:这个临时变量具有常性,不可修改。

int main()
{
	double j = 1.1;
	int i = j;//隐式类型转换
	int& a = j;//error
	const int& b = j;//ok
	return 0;
}

因为临时变量具有常性,所以无法被修改。如果赋值给普通引用就会造成权限的放大,所以只能用常引用。 

2.2. 自定义类型 

如果将一个内置赋值给自定义类型,那么编译器也会先创造一个自定义类型的**临时变量,**然后用这个内置类型调用构造函数对临时变量初始化最后用这个临时变量对左操作数进行拷贝构造。。注意:这个临时变量也具有常性,不可修改。 

 

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1 = 2023;//发生隐式类型转换
	Date d2 = { 2023,2 };
	d1.Print();
	d2.Print();
	return 0;
}
2.3. explicit关键字

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

class Date
{
public:
	explicit Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1 = 2023;//发生隐式类型转换
	Date d2 = { 2023,2 };
	d1.Print();
	d2.Print();
	return 0;
}

 

 3.类的静态成员 

2.1. 定义

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数

class A
{
public:
    static int Print()//静态成员函数
	{
		cout << "Print()" << endl;
	}
private:
	static int _a;//静态成员变量
};
2.2. 注意
  1. 静态成员也是类的成员,受public、protected、private 访问限定符的限制。
  2. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。所以可以通过类名::静态成员或者 对象.静态成员来访问。
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

class A
{
public:
	static void Print()//静态成员函数
	{
		cout << "Print()" << endl;
	}
private:
	static int _a;//静态成员变量
};
int main()
{
	A a;
	a.Print();
	A::Print();
	return 0;
}

 

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

int A::_a = 1;//类外定义

 4.静态成员函数没有隐藏的this指针,不能访问任何非静态成员。比如说:静态函数就无法访问非静态函数。

	static void Print()//静态成员函数
	{
		cout << "Print()" << endl;
		Add(1, 2);//无法访问非静态成员
	}
	int Add(int x, int y)
	{
		return x + y;
	}

但是非静态成员函数能访问静态成员函数。 

	static void Print()//静态成员函数
	{
		cout << "Print()" << endl;
	}
	int Add(int x, int y)
	{
		return x + y;
		Print();
	}

4.const成员函数

将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后
⾯。
• const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。
const 修饰Date类的Print成员函数,Print隐含的this指针由Date* const this 变为 const Date* const this

#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// void Print(const Date* const this) const
void Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
// 这⾥⾮const对象也可以调⽤const成员函数是⼀种权限的缩⼩
Date d1(2024, 7, 5);
d1.Print();
const Date d2(2024, 8, 5);
d2.Print();
return 0;
}

 

5. 友元 

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

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

5. 1友元函数

有时在类外我们需要访问类中的数据,但由于访问限定符的限制并不能访问私有成员。这时如果一定要访问的话就需要借助我们的友元函数,它的用法十分简单,只用在类中加friend+该函数的声明

class Date
{
	friend void Print(const Date& d);//友元函数
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
void Print(const Date&d)
{
	cout << d._year << "-" << d._month << "-" << d._day << endl;
}

也能通过在类中声明获取私有元素的返回函数实现: 

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	int GetYear()const
	{
		return _year;
	}
	int GetMonth()const
	{
		return _month;
	}
	int GetDay()const
	{
		return _day;
	}
private:
	int _year;
	int _month;
	int _day;
};
void Print(const Date& d)
{
	cout << d.GetYear() << "-" << d.GetMonth() << "-" << d.GetDay() << endl;
}
5.2. 友元类 

除了友元函数外,还有一种友元类。友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。与友元函数用法类似:在一个类中声明friend+class+类名 

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 = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	void SetTimeOfDate(int hour, int minute, int second)
	{
		// 直接访问时间类私有的成员变量
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};

1.*友元关系是单向的,不具有交换性。**比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
2.**友元关系不能传递。**如果C是B的友元, B是A的友元,则不能说明C时A的友元。

6. 内部类 

6.1. 定义

如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。并且内部类就是外部类的友元类。

class A
{
public:
	class B//B是A的友元
	{
	private:
		int _m;
	};
private:
	int _a;
	int _b;
};
6.2. 注意
  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象 / 类名。
class A
{
private:
	static int k;
	int h;
public:
	class B // B天生就是A的友元
	{
	public:
		void foo()
		{
			cout << k << endl;//OK
		}
	};
};
int A::k = 1;
int main()
{
	A::B b;
	b.foo();
	return 0;
}

 

7. 匿名对象

7.1匿名对象

匿名对象与C语言中的匿名结构体类似,只有类名,作用域只在匿名对象声明的一行。

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		cout << "Date" << endl;
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d)" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
	~Date()
	{
		cout << "~Date()" << endl;
		_year = _month = _day = 0;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date();//匿名对象
	Date d;
	return 0;
}

 

7.2延长生命周期的匿名对象 

      为什么匿名对象用一次就会销毁呢??本质来说是因为他没有名字,所以没有人能用得了他,就没有存在的意义了

    但是如果我们给他起了一个别名,就有意义了,但是由于匿名对象具有常性,所以必须用const引用。

 

int main()
{
	const Date& dc = Date();//匿名对象也具有常性
	Date d;
	return 0;
}

 

const引用会延长匿名对象的生命周期和他的别名一样 ,使用他的别名就是在使用他! 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

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

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

相关文章

手撕布隆过滤器:原理解析与面试心得

前言 说来话长&#xff0c;话来说长。前些天我投了一些日常实习的简历&#xff0c;结果足足等了两个礼拜才收到面试通知&#xff0c;看来如今的行情确实是挺紧张的。当时我是满怀信心去的&#xff0c;心想这次一定要好好拷打面试官一番&#xff0c;结果没想到&#xff0c;自我…

一、python基础

python基础 认识Python1. Python介绍1.1 为什么学习Python1.2 Python发展历史 2. 语言分类简介2.1 编译型2.2 解释型 Python环境搭建1. Python 解释器1.1 Python解释器下载1.2 Python解释器安装 2. 解释器运行Python脚本2.1 演练步骤 PyCharm1. PyCharm介绍2. PyCharm安装3. Py…

15分钟学Go 第6天:变量与常量

第6天&#xff1a;变量与常量 在Go语言中&#xff0c;变量和常量是编程的基础概念。理解如何定义和使用它们不仅能帮助我们管理数据&#xff0c;还能增强代码的可读性和可维护性。在本章中&#xff0c;我们将详细探讨Go语言中的变量和常量&#xff0c;涵盖它们的定义、使用、作…

机器学习建模分析

机器学习 5.1 机器学习概述5.1.1 机器学习与人工智能5.1.2 python机器学习方法库 5.2 回归分析5.2.1 回归分析原理5.2.2 回归分析实现 5.3 分类分析5.3.1 分类学习原理5.3.2 决策树5.5.3 支持向量机 5.4 聚类分析5.4.1 聚类任务5.4.2 K-means算法 5.5 神经网络和深度学习5.5.1神…

python配合yolov11开发分类训练软件

上一篇文件写了用yolo分类模型开发分类软件&#xff0c;这边文章在上个分类软件的基础上加入训练功能环境配置:pycharm&#xff0c;PySide6 6.6.1 &#xff0c;PySide6-Addons 6.6.1&#xff0c;PySide6-Essentials 6.6.1&#xff0c;torch 2.3.1cu121&#xff0c;torchaudio 2…

dynadot设置域名动态DNS(DDNS)

需求&#xff1a;本地测试代理&#xff0c;代理需要绑定IP或者域名&#xff0c;本地IP是动态变化的&#xff0c;解决办法就是给域名设置动态DNS 1.dynadot设置 开启动态DNS选项会显示动态DNS密码&#xff0c;该密码后续将会用在DDNS-GO工具上 2.DDNS-GO设置 GitHub介绍页面&a…

WIFI、NBIOT、4G模块调试AT指令连接华为云物联网服务器(MQTT协议)

一、前言 随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;越来越多的设备开始连接到互联网&#xff0c;形成了一个万物互联的世界。在这个背景下&#xff0c;设备与云端之间的通讯变得尤为重要。 本文将探讨几种常见的无线通信模块——EC20-4G、Air724ug-4…

每天花2分钟学数字化转型,第四讲:数字化转型

一文看懂&#xff1a;数字化转型是什么&#xff1f;以及数字化转型的根本任务与核心路径。 定义&#xff1a;数字化是人类社会的进化&#xff0c;绝不仅仅是一个企业的问题&#xff0c;也不是某一项技术的问题&#xff0c;而是时代的变迁。数字化转型指的是从当前信息化环境下…

RabbitMQ系列学习笔记(三)--工作队列模式

文章目录 一、工作队列模式原理二、工作队列模式实战1、抽取工具类2、消费者代码3、生产者代码4、查看运行结果 本文参考 尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmq RabbitMQ 详解 Centos7环境安装Erlang、RabbitMQ详细过程(配图) 一、工作队列模式原理 与简单模式相…

企业级 接口自动化测试框架:Pytest+Allure+Excel

1. Allure 简介 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具&#xff0c;它不仅以 Web 的方式展示了简介的测试结果&#xff0c;而且允许参与开发过程的每个人可以从日常执行的测试中&#xff0c;最大限度地提取有用信息。 Allure 是由 Java 语言开发…

MySQL 【日期】函数大全(七)

目录 1、UNIX_TIMESTAMP() 将指定的日期/日期时间转为 UNIX 时间戳值。 2、WEEK() 返回给定日期位于当年的第几周。 3、WEEKDAY() 返回给定日期的工作日编号。 4、WEEKOFYEAR() 返回给定日期位于当年的第几周 5、YEAR() 提取日期的年份部分并作为数字返回。 6、YEARWEEK()…

Jmeter 实战 JDBC配置

​ JDBC JDBC&#xff08;Java Database Connectivity&#xff09;是一种用于执行SQL语句的Java API。通过这个API&#xff0c;可以直接连接并执行SQL脚本&#xff0c;与数据库进行交互。 使用JMeter压力测试时&#xff0c;操作数据库的场景 在使用JMeter进行接口压力测试时…

Gin 协程mysql客户端

一、Gin框架 mysql配置 这里选择yaml文件配置 二、配置读取 viper 读取yaml文件中对应配置 三、mysql 的协程客户端 文件位置 package databaseimport ("database/sql""fmt""github.com/spf13/viper""log""net/http"&quo…

JavaWeb 25.Vite

目录 一、Vite的介绍 二、Vite创建Vue3工程化项目 ViteVue3项目的创建、启动、停止 创建 启动 停止 干净感来源于对自我的驯服 —— 24.10.23 一、Vite的介绍 在浏览器支持 ES 模块之前&#xff0c;JavaScript 并没有提供原生机制让开发者以模块化的方式进行开发。这也正是我们…

Missing classes detected while running R8报错解决方案

Android 打包release版本时报错如下&#xff1a; > Task :printlib:minifyReleaseWithR8 FAILED AGPBI: {"kind":"error","text":"Missing classes detected while running R8. Please add the missing classes or apply additional ke…

canvas-editor首行缩进

canvas-editor中渲染部分的源码都在Draw.ts里&#xff0c;能找到computeRowList方法中并没有实现首行缩进相关的逻辑&#xff0c;但是实现了element.type ElementType.TAB的缩进&#xff0c;如图&#xff1a; 因此我们可以基于tab进行首行缩进的逻辑编写&#xff0c;在main.ts…

通过DevTools逃离Chrome沙盒(CVE-2024-6778和CVE-2024-5836)

介绍 这篇博文详细介绍了如何发现CVE-2024-6778和CVE-2024-5836的&#xff0c;这是Chromium web浏览器中的漏洞&#xff0c;允许从浏览器扩展&#xff08;带有一点点用户交互&#xff09;中进行沙盒逃逸。 简而言之&#xff0c;这些漏洞允许恶意的Chrome扩展在你的电脑上运行…

2015年-2017年 计算机技术专业 程序设计题(算法题)实战_c语言程序设计数据结构程序设计分析

文章目录 20151.C语言算法设计部分2.数据结构算法设计部分 20161.C语言算法设计部分2.数据结构算法设计部分 2017年1. C语言算法设计部分2.数据结构算法设计部分 2015 1.C语言算法设计部分 int total(int n) {if(n1) return 1;return total(n-1)n1; } //主函数测试代码已省略…

Android 15 推出新安全功能以保护敏感数据

Android 15 带来了增强的安全功能&#xff0c;可保护您的敏感健康、财务和个人数据免遭盗窃和欺诈。 它还为大屏幕设备带来了生产力改进&#xff0c;并对相机、消息和密钥等应用进行了更新。 Android 防盗保护 Google 开发并严格测试了一套全面的功能&#xff0c;以在盗窃之…

Ubuntu22.04 制作系统ISO镜像

第一步&#xff1a;安装软件-Systemback 1.如果已经添加过ppa&#xff0c;可以删除重新添加或者跳过此步 sudo add-apt-repository --remove ppa:nemh/systemback 2.添加ppa 我是ubuntu20&#xff0c;但这个软件最后支持的是 ubuntu16.04版本&#xff0c;所以加一个16版本…