C++再谈构造函数、隐式类型转换、static成员、友元函数、内部类等的介绍

目录

  • 前言
  • 一、再谈构造函数
    • 1. 构造函数体赋值
    • 2. 初始化列表
    • 3. 初始化列表初始化顺序
    • 4. 初始化隐式类转换
  • 二、static成员
    • 1. 概念
    • 2. 特性
  • 三、 友元
    • 1. 友元函数
    • 2. 友元类
  • 四、内部类
  • 总结

前言

C++再谈构造函数、隐式类型转换、static成员、友元函数、内部类等的介绍


一、再谈构造函数

1. 构造函数体赋值

 class Date
{
public:
	Date(int year = 1945, int month = 8, int day = 15)
	{
		_year = year;
		_month = month;
		_day - day;
	}
private:
	int _year;
	int _month;
	int _day;
};

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,

构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值

2. 初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表每个"成员变量"后面跟一个放在括号中的初始值或表达式
初始化列表书写在构造函数的函数名下面一行。如下:

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

【注意】

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)
#include <iostream>
using namespace std;

class A
{
public:
	A(int a)
	{
		_a = a;
	}
private:
	int _a;
};


class B
{
public:
	B(int a, int ret)
		: _aobj(a)
		, _ret(ret)
		, _n(10)
	{}
private:
	A _aobj; // 没有默认构造函数
	int& _ret; // 引用
	const int _n; // const修饰
};

int main()
{

	B b1(20, 30);

	return 0;
}

注意:
没有默认构造函数是: 没有编译器默认生成的构造函数,没有全缺省参数的构造函数,没有无参的构造函数。

尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。c++11的补丁,可以对内置类型声明设置缺省值,本质上是在初始化列表中进行初始化的。

3. 初始化列表初始化顺序

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

#include <iostream>
using namespace std;

class A
{
public:
	A(int a)
		: _a2(a)   // 本意上,希望先给_a2赋值,再将_a2赋值给_a1,初始化列表的顺序与声明的顺序一致
		, _a1(_a2)  //  所以先将_a2(此时_a2是随机值)赋值给_a1,再将 a 赋值给_a2
	{}
private:
	int _a1;
	int _a2;
};

int main()
{
	A a(10);

	return 0;
}

本意上,希望先给_a2赋值,再将_a2赋值给_a1,初始化列表的顺序与声明的顺序一致
所以先将_a2(此时_a2是随机值)赋值给_a1,再将 a 赋值给_a2,结果如下:

在这里插入图片描述

4. 初始化隐式类转换

#include <iostream>
using namespace std;

class A
{
public:
	A(int a)
		: _a(a)
	{}

private:
	int _a;
};


int main()
{
	A aa1(10);
	A aa2 = 10;

	return 0;
}
  • A aa1(10),这种方式是直接调用构造函数进行初始化。
  • A aa2 = 10, 这种方式是隐式类型转换。
    先使用构造函数将10转换为A类型,产生一个临时对象;
    再调用拷贝构造函数将临时对象拷贝给aa2。
    但是编译器基本都会优化,用10直接进行构造。

在这里插入图片描述


在这里插入图片描述

如上图:
先调用构造函数将10构造为一个临时的对象。
临时对象具有常性 所以10构造的临时对象类型为 const A。
使用拷贝构造将临时对象拷贝给A& aa3,类型权限放大了所以会报错。加const修饰则可以完成。

在这里插入图片描述

若要限制隐式类型转换,可以在构造函数前加 explicit 关键字

#include <iostream>
using namespace std;

class A
{
public:
	explicit A(int a)
		: _a(a)
	{}

private:
	int _a;
};


int main()
{

	A aa1 = 2;


	return 0;
}

在这里插入图片描述

二、static成员

1. 概念

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

注意:
成员变量属于每一个类,存储在对象里边
静态成员变量属于类,为所有类实例化产生的对象共享。存储子啊静态区。

例如:写一个类计算创建了多少个类对象

#include <iostream>
using namespace std;

class A
{
public:
	A() { ++_source; }
	A(const A& a) { ++_source; }
	~A() { --_source; }
	void Init()
	{
	}

	static int GetSource() {
		return _source;
	}

private:
	static int _source;
};

// static修饰的成员变量在类外进行初始化
int A::_source = 0;

A a1;

void Func()
{
	A a3;
	cout << __LINE__ << ":" << A::GetSource() << endl;

}
int main()
{
	cout << __LINE__ << ":" << A::GetSource() << endl;
	A a2;

	cout << __LINE__ << ":" << A::GetSource() << endl;

	Func();
	cout << __LINE__ << ":" << A::GetSource() << endl;

	return 0;
}

在这里插入图片描述

2. 特性

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

注意:

  1. 静态成员函数不可以调用非静态成员函数,因为成员函数调用需要this指针,但是静态成员函数没有this指针
  2. 非静态成员函数可以调用类的静态成员函数

设计一个类,在类外面只能在栈上创建类对象
设计一个类,在类外面只能在堆上创建类对象


// 设计一个类,在类外面只能在栈上创建类对象
// 设计一个类,在类外面只能在堆上创建类对象

#include <iostream>
using namespace std;

class A
{
public:
	static A GetStackObj()
	{
		A aa;
		return aa;
	}

	static A* GetHeapObj()
	{
		A aa;
		return new A;
	}
private:
	A()
	{}
private:
	int _a;
};

int main()
{
	A::GetStackObj();

	A::GetHeapObj();


	return 0;
}

三、 友元

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

1. 友元函数

日期类中需要重载operator<<,发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。
参考: 日期类的完整实现

友元函数可以直接访问类的私有成员,它是定义在类外部普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

说明:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

2. 友元类

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

  • 友元关系是单向的,不具有交换性。
    比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  • 友元关系不能传递
    如果B是A的友元,C是B的友元,则不能说明C时A的友元。
  • 友元关系不能继承。
#include <iostream>
using namespace std;

class Time
{
	// 将Date类设置为Time类的友元类
	friend class Date;
public:
	Time(int hour = 8, int minute = 30, int second = 30)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{

	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	Date(int year = 1368, int month = 1, int day = 4)
		: _year(year)
		, _month(month)
		, _day(day)
	{


	}
	// 在Date类中可以直接访问修改time类中的三个私有成员变量
	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;
};

int main()
{

	return 0;
}

四、内部类

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

注意:内部类就是外部类的友元类(内部类是外部类的“天然”友元类),内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系
#include <iostream>
using namespace std;

class A
{
private:
	static int k;
	int _a;
public:
	A(int a = 100)
		: _a(a)
	{}
	class B
	{
	private :
		int b;
	public:
		void foo(const A& a)
		{
			cout << k << endl;
			cout << a._a << endl;
		}
	};
};

int A::k = 666;

int main()
{
	A a1; // 创建a1对象与类B无关

	// B b; // 不能直接使用类B创建实例化对象
	
	A::B b1; // 要使用B实例化对象需要采用这种形式

	b1.foo(a1);

	return 0;
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结

C++再谈构造函数、隐式类型转换、static成员、友元函数、内部类等的介绍

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

imx6ull/linux应用编程学习(3) 输入设备应用编程(上)(按键)

0.概念 输入设备&#xff1a;可以产生输入事件的设备 Linux系统设计了一个兼容所有输入设备的框架&#xff0c;就是input子系统&#xff0c;其直接向应用层提供了一套统一的接口&#xff0c;其在/dev/input目录下。 流程&#xff1a;如果要读取输入设备&#xff0c;一般遵循以下…

Spring AOP实战--之优雅的统一打印web请求的出参和入参

背景介绍 由于实际项目内网开发&#xff0c;项目保密&#xff0c;因此本文以笔者自己搭建的demo做演示&#xff0c;方便大家理解。 在项目开发过程中&#xff0c;团队成员为了方便调试&#xff0c;经常会在方法的出口和入口处加上log输出&#xff0c;由于每个人的log需求和输…

IOS17闪退问题Assertion failure in void _UIGraphicsBeginImageContextWithOptions

最近项目更新到最新版本IOS17&#xff0c;发现一个以前的页面突然闪退了。原来是IOS17下&#xff0c;这个方法 UIGraphicsBeginImageContext(CGSize size) 已经被移除&#xff0c;原参数如果size为0的话&#xff0c;会出现闪退现象。 根据说明&#xff0c;上述方法已经被替换…

《UDS协议从入门到精通》系列——图解0x38:请求上传

《UDS协议从入门到精通》系列——图解0x38&#xff1a;请求上传 一、简介二、数据包格式2.1 服务请求格式2.2 服务响应格式2.2.1 肯定响应2.2.2 否定响应 三、通信示例 Tip&#x1f4cc;&#xff1a;本文描述中但凡涉及到其他UDS服务的&#xff0c;将陆续提供链接跳转方式以便快…

MySQL数据库存储引擎

MySQL数据库存储引擎 存储引擎概念 存储引擎也称为表类型 通过不同的技术比如说&#xff0c;存储机制&#xff0c;索引技巧&#xff0c;锁定水平等等&#xff0c;来提供不同的功能。 查看MySQL支持的存储引擎 show engines\G&#xff1b; 常用引擎比较 对事务有需求 innodb …

蚂蚁- 定存

一&#xff1a;收益变动&&收益重算 1.1: 场景组合 1: 澳门元个人活期&#xff0c;日终余额大于0&#xff0c;当日首次、本周本月非首次系统结息&#xff0c;结息后FCDEPCORE_ASYN_CMD_JOB捞起进行收益计算 【depc_account_revenue_detail】收益日 > 【depc_accoun…

【Unity Linux】模型导致的Unity项目崩溃

模型需勾选Strip Bones。如不勾选&#xff0c;则开启项目崩溃。 也可以删除有问题模型的.meta文件。 &#xff08;Unity默认会自动勾选&#xff0c;所以不会崩溃&#xff09; 或打开.meta文件&#xff0c;将optimizeBones的值&#xff0c;由0改为1。&#xff08;对应面板上的…

实时智能全托管-云器Lakehouse重新定义多维数据分析

导读 本文将分享云器Lakehouse如何重新定义实时多维分析&#xff0c;帮助客户实现实时、智能、全托管的数据平台。主要内容包括以下几大部分&#xff1a; 多维数据分析的发展趋势和场景解析 技术解析&#xff1a;新一代数平台Lakehouse如何支持实时分析需求 价值解析&#x…

java 统计xmind的结点数(测试用例case数)

mac电脑解压出来的xmind的数据主要在content.json上 开头结尾有[],里面是json import org.json.JSONArray; import org.json.JSONObject; import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream;public class XMindLeafCounter2 {public stat…

【观察】戴尔科技+AMD:释放技术创新“乘数效应”,助力制造业打造“新质生产力”...

在今年的政府工作报告中&#xff0c;“人工智能”首次被写入报告&#xff0c;同时“大力推进现代化产业体系建设&#xff0c;加快发展新质生产力”也被列为2024年的首项政府工作任务&#xff0c;其重要性不言而喻。 尤其是最近几年&#xff0c;以人工智能、大模型、大数据、云计…

【漏洞复现】万户-ezOFFICE download_ftp.jsp 任意文件下载漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

讲座学习截图——《CAD/CAE/CAM几何引擎-软件概述》(一)

目录 引出CAD/CAE/CAM几何引擎-软件概述 郝建兵CADCAECAM 几何模型内核ACIS 两个老大之一Open CascadeParasolid 两个老大之一Autodesk的内核 总结其他自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进行触发 自定义信号重载带参数的按钮触发信号触发信号拓展 lambda表达式…

linux中find命令和exec的强大组合用法

如何将 find 命令与 exec 一起使用 Find 是一个已经非常强大的命令&#xff0c;用于根据许多条件搜索文件。exec 命令使您能够处理 find 命令的结果。 我在这里分享的例子只是一瞥。find-exec 命令组合在一起为您提供了在 Linux 命令行中执行操作的无限可能。 find 和 exec 命令…

[leetcode]longest-arithmetic-subsequence-of-given-difference. 最长定差子序列

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int longestSubsequence(vector<int> &arr, int difference) {int ans 0;unordered_map<int, int> dp;for (int v: arr) {dp[v] dp[v - difference] 1;ans max(ans, dp[v]);}return ans…

基于单片机的智能温控风扇设计

摘 要 : 本次设计是基于单片机的智能温控风扇 。 以 STC89C52 单片机为核心 &#xff0c; 可以实现对风扇的有效控制 。 可以根据需要设置不同的温度 &#xff0c;如果温度在设定值最大值和最小值之间时则启动风扇弱风档&#xff0c; 如果温度超过设定的数值时将会变到大风档…

【Android面试八股文】Framework面试:Handler怎么进行线程通信的?原理是什么?

文章目录 Handler整体思想Handler工作流程Handler工作流程图总结Handler整体思想 在多线程的应用场景中,将工作线程中需更新 UI 的操作信息 传递到 UI 主线程,从而实现 工作线程对 UI 的更新处理,最终实现异步消息的处理。 Handler工作流程 Handler 机制的工作流程主要包括…

pytest测试框架pytest-html插件生成HTML格式测试报告

Pytest提供了丰富的插件来扩展其功能&#xff0c;pytest-html插件帮助我们生成HTML格式的测试报告&#xff0c;为我们提供直观、有效的测试结果展示。 为了使用 pytest-html&#xff0c;需要满足以下条件&#xff1a; Python 3.6 或更高版本 pytest-html安装 使用pip命令安…

【scrapy】3.XPath解析

目录 一、XPath介绍 1.基本介绍 2.HTML树状结构图 3.节点之间的关系 &#xff08;1&#xff09;Xpath中的绝对路径与相对路径 二、XPath的语法介绍 1.元素属性定位 1.1 根据属性名定位元素&#xff1a; 1.2 根据属性名和属性值定位元素&#xff1a; 1.3 根据部分属性…

C语言力扣刷题1——最长回文字串[双指针]

力扣算题1——最长回文字串[双指针] 一、博客声明二、题目描述三、解题思路1、思路说明2、知识补充a、malloc动态内存分配b、free释放内存c、strlen求字符数组长度d、strncpy函数 四、解题代码&#xff08;附注释&#xff09; 一、博客声明 找工作逃不过刷题&#xff0c;为了更…

Swagger与RESTful API

1. Swagger简介 在现代软件开发中&#xff0c;RESTful API已成为应用程序间通信的一个标准。这种架构风格通过使用标准的HTTP方法来执行网络上的操作&#xff0c;简化了不同系统之间的交互。API&#xff08;应用程序编程接口&#xff09;允许不同的软件系统以一种预定义的方式…