C++初阶:类与对象(尾篇)

目录

  • 1. 构造函数与初始化列表
    • 1.1 对象的创建与构造函数的初始化
    • 1.2 初始化列表及构造函数存在的意义
    • 1.3 explicit关键字与构造函数的类型转换
  • 2. static成员变量与static成员函数
    • 2.1 static成员变量
    • 2.2 static成员函数
  • 3. 日期类流插入操作符的重载与友元
    • 3.1 友元
    • 3.2 友元函数
    • 3.3 友元类
  • 4. 内部类
  • 5. 匿名对象
  • 6. 拷贝对象时编译器可能会进行的一些优化

1. 构造函数与初始化列表

1.1 对象的创建与构造函数的初始化

  1. 在前面的学习中,我们尝试了对简单类(日期类)进行了实现,而后在使用中我们通过定义类模板然后实例化的方式,创建我们所需要的对象。
  2. 在这一过程中,编译器按照所指定的类型去相应的内存区域中申请空间,在已经创建好变量后,再调用构造函数对生成的对象进行初始化。
  3. 大多数情况下,这种初始化的方式都不会出现问题,可是当类的成员变量中有一些特定的类型比如,const修饰的变量引用类型的变量没有默认构造函数的自定义类型,此时,这种初始化方式就行不通了。(默认构造函数:编译器自动生成,无参数,有缺省参数)

1.2 初始化列表及构造函数存在的意义

  1. 内置类型可以在创建变量申请空间时就进行变量的初始化,而自定义类型是否也可以在创建变量的同时就进行初始化,它的初始化方式是什么,接下来,我们引出类与对象中的初始化列表。
  2. 类实例化生成对象时并不是只开辟空间,对空间中的内容不做处理,而是会调用初始化列表对开辟出的空间进行初始化。前面之所以无法对特殊类型无法进行初始化,是因为我们没有向初始化列表中添加内容。
  1. 初始化列表的定义方式:
//构造函数
class A
{
private:
	int _a;
	int _b;
	int _c
	
	//构造函数,函数体之前,语法如下:
	A(int a, int b ,int c)
	:_a(a)
	,_b(b)
	,_c(c)
	{}
}
  1. 初始化列表的调用方式:(三种必须用初始化列表进行初始化的成员变量)
//没有缺省参数
class A
{
public:
	A(int d)
	{
		_d = d;
	}

	int _d;
};

class B
{
public:
	const int _a;
	int& _b;
	A _c;

	//构造函数
	B(int b, int c)
		:_a(10)
		,_b(b)
		,_c(c)
	{
		cout << " _a = " << _a << " _b = " << _b << " _c._d = " << _c._d << endl;
	}
};

int main()
{
	int b = 20;
	int c = 30;
	B a(b, c);

	return 0
}
  1. 初始化列表初始化成员变量的顺序:
    初始化列表进行初始化的顺序是根据成员变量的声明顺序决定的
class A
{
public:
	int _b;
	int _a;
	
	//先初始化_a,再初始化_b
	A(int a = 0)
		:_a(a)
		,_b(_a)
	{}

	void Print()
	{
		cout << _a << ' ' << _b << ' ' << endl;
	}
};

int main()
{
	A a(10);
	a.Print();

	return 0;
}

执行结果:使用成员变量_a初始化成员变量_b时,_a还没有被初始化
在这里插入图片描述

  1. <1> 既然初始化列表可以进行初始化,并且初始化列表能做到构造函数无法做到的特殊类型成员的声明,那么,为什么还要有构造函数呢?
    <2> 初始化列表能做的只有初始化,无法对初始化后的变量做检查与合法性判断
class A
{
public:
	int* _a;

	A(int n)
		:_a((int*)malloc(n * sizeof(int)))
	{
		if (_a == nullptr)
		{
			perror("malloc failed");
			exit(-1);
		}
	}
};

1.3 explicit关键字与构造函数的类型转换

  1. 类的默认成员函数operator=重载,其构造函数在只有单参数或拥有缺省参数,支持用与成员变量类型相同的数据,变量直接进行赋值操作。
class Date
{
public:
	int _year;
	int _month;
	int _day;

	Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}

		return *this;
	}
};

int main()
{
	Date d1(2024);
	d1 = 2025;
	int year = 2026;
	d1 = year;
	
	cout << d1._year << '-' << d1._month << '-' << d1._day << endl;
	
	return 0;
}

支持上述操作的原因,是因为数据或者变量会进行类型转换构造临时对象,然后再用临时构造出的对象进行赋值操作

  1. explicit关键字,修饰构造函数,使得这个构造函数所在的类其,实例化的对象不会发生类型转换的操作。
class Date
{
public:
	int _year;
	int _month;
	int _day;

	explicit Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
};

2. static成员变量与static成员函数

2.1 static成员变量

  1. 静态成员变量也是类的成员之一,它不独属于某个对象,而是属于这个类,为所有实例化对象所共有,存放在静态区。
  2. 静态成员变量在类中声明,在类外定义,在类外定义时不需要加static关键字。
  3. 静态成员变量的调用方式为,对象.静态成员变量类区域::静态成员变量
  4. 静态成员变量也受访问限定符的限制
class A
{
public:
	static int _count;

	A()
	{
		++_count;
	}

	A(const A& a)
	{
		++_count;
	}

	~A()
	{
		--_count;
	}
};

int A::_count = 0;

int main()
{
	A a1;
	cout << a1._count << endl;
	a1.~A();
	cout << A::_count << endl;

	return 0;
}

2.2 static成员函数

  1. 与静态成员变量类似,静态成员函数也是属于全体实例化对象,而不是属于某个对象。
  2. 静态成员函数的定义方式,也是类内声明类外定义。
  3. 静态成员函数没有this指针,不能调用非静态成员变量。
  4. 静态成员函数的调用方式,对象.静态成员函数类域::静态成员函数
  5. 同样的静态成员函数也受访问限定符限制。
class A
{
//public:
	static int _count;
	static int GetCount();
public:
	//非静态成员函数可以调用静态成员函数
	void Print()
	{
		cout << (*this).GetCount() << endl;
		cout << "hello" << endl;
	}

	A()
	{
		++_count;
	}

	A(const A& a)
	{
		++_count;
	}

	~A()
	{
		--_count;
	}
};

int A::_count = 0;
int A::GetCount()
{
	//静态成员函数没有this指针
	//无法调用非静态成员函数
	return A::_count;
}

3. 日期类流插入操作符的重载与友元

  1. 当我们尝试对实现过的日期类进行流插入运算的重载时,当把它作为成员函数时,我们发现无法实现。
  2. 操作数的次序为操作符重载函数的参数从左往右,分别是操作符的第一个,第二个…操作数。
  3. 成员函数的一个参数都为隐藏的默认参数this指针,而流插入操作符的需要的第一个参数是ostream类型的变量。可是,当我们不使用成员函数的方式实现,那么函数就无法访问private访问限定符修饰的成员变量。
  1. 那么,流插入操作符的重载就无法实现吗,这里我们引入C++新的内容,友元

3.1 友元

  1. 友元关系的实际应用分为友元类与友元函数,这是一种突破类访问限定符封装的方式,它在提供了这种功能的同时,也不可避免地增加了代码的耦合性,不建议多用。

3.2 友元函数

  1. 友元函数是普通函数,它定义在类外。而它达成友元的方式为,在类中对其进行友元声明。
  2. 友元函数可以在类中的任何地方声明,不受访问限定符影响。
  3. 友元函数的声明方式为,在普通的函数声明前加关键字friend
  4. 一个函数可以是多个类的友元函数。
class Date
{
public:
	int _year;
	int _month;
	int _day;

	Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& out, const Date& d);
};

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << '-' << d._month << '-' << d._day;

	return out;
}

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	
	return in;
}

3.3 友元类

  1. 友元类的所有成员函数都是另一个类的友元函数,可以访问另一个类的所有私有成员。
  2. 友元类关系是单向的。
  3. 友元关系不可传递,A类是B类友元,B类是C类的友元,A类不是C类的友元,不可以访问C类。
  4. 友元关系不能被继承
  5. 友元类的声明方式为,在需要被访问的类中声明其的友元类,friend + 类名
class Time
{
public:
	Time(int hour = 0, int minute = 0, int seconds = 0)
		:_hour(hour)
		, _minute(minute)
		, _seconds(seconds)
	{}

	friend class Date;

private:
	int _hour;
	int _minute;
	int _seconds;
};

class Date
{
public:
	int _year;
	int _month;
	int _day;
	Time _t;

	Date(int year, int month = 1, int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}

	void SetTime()
	{
		_t._hour = 21;
		_t._minute = 25;
		_t._seconds = 0;

		cout << _t._hour << '/' << _t._minute << '/' << _t._seconds << endl;
	}
};

4. 内部类

  1. 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。
  2. 外部类对内部类没有访问权限。
  3. 内部类只是在外部类中声明,外部类计算大小时不包含内部。(sizeof(外部类)单纯只是外部类的大小)
  4. 内部类对外部类天生就是友元,并且可以直接访问外部类的静态成员变量与函数,无需指定类域。
  5. 内部类可以在任意访问限定符的区域声明,在private中时,无法进行内部类的调用实例化对象。
class A
{
private:
	int _a;
	static int _c;

public:
	class B
	{
	public:
		void test(A& x)
		{
			x._a = 10;
			_c = 20;

			cout << x._a << endl;
			cout << x._c << endl;
		}
	};
};

int A::_c = 0;

int main()
{
	A x;
	//內部类对象的声明
	A::B h;
	h.test(x);

	return 0;
}

5. 匿名对象

  1. 在实例化对象时,省略对象名的创建方式。
  2. 匿名对象的声明周期只有一行,紧接着下一行时,就会调用析构函数将其销毁。
class A
{
private:
	int _ a;
public:
	A(int a = 0)
	{
		cout << _a << endl;
	}

	void Print()
	{
		cout << "hello world" << endl;	
	}
};

//不支持此种调用构造函数的方式,因为无法识别其为函数的声明还是析构函数的调用
A a1();

//创建匿名对象的方式
A();

//匿名对象调用成员函数
A().Print();

6. 拷贝对象时编译器可能会进行的一些优化

  1. 在成员函数传参和传返回值的过程中,一般编译器会做一些优化,减少不必要对象的拷贝
  2. 在同一行中,连续的构造,拷贝构造操作编译器会进行优化:
    <1> 构造 + 拷贝构造 优化为 构造
    <2> 连续的构造 + 拷贝构造 优化为 直接构造
    <3> 连续的拷贝构造 优化为 直接进行拷贝构造
class C
{
private:
	int _c;
public:
	C(int c)
	{
		cout << "C()" << endl;
	}

	C(const C& tmp)
	{
		cout << "C(const C&)" << endl;
	}
};

int main()
{
	//构造 + 拷贝构造,类型转换,生成临时对象
	C c1(2);

	return 0;
}

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

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

相关文章

Ubuntu20.04配置静态ip

文章目录 前言配置静态ip 前言 在 Linux 创建时默认是动态 ip&#xff0c;我们需要将这台 Linux 作为服务器&#xff0c;所以需要将动态分配的 ip 设置为静态的&#xff0c;防止 ip 变换。 可使用 ip addr 查看当前的 网卡 和 ip 信息&#xff1a; 从上图可看到动态分配的 i…

Python 导入Excel三维坐标数据 生成三维曲面地形图(体) 5-1、线条平滑曲面且可通过面观察柱体变化(一)

环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata fr…

HAProxy 简单介绍

一 HAProxy介绍 &#xff08;一&#xff09;发展历史 HAProxy是法国开发者威利塔罗(Willy Tarreau)在2000年使用C语言开发的一个开源软件&#xff0c;是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器&#xff0c;支持基于cookie的持久性&#xff0c;自动故障切换…

GPT与R 在生态环境领域数据统计分析

原文链接&#xff1a;GPT与R 在生态环境领域数据统计分析https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247597092&idx2&sn0a7ac5cf03d37c7b4659f870a7b71a77&chksmfa823dc3cdf5b4d5ee96a928a1b854a44aff222c82b2b7ebb7ca44b27a621edc4c824115babe&…

软件杯 垃圾邮件(短信)分类算法实现 机器学习 深度学习

文章目录 0 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 垃圾邮件(短信)分类算…

实战案例——Kafka集群部署

1. 规划节点 IP主机名节点192.168.100.10zookeeper1集群节点192.168.100.20zookeeper2集群节点192.168.100.30zookeeper集群节点 2. 基础准备 使用ZooKeeper集群搭建的3个节点来构建Kafka集群&#xff0c;因为Kafka服务依赖于ZooKeeper服务&#xff0c; 所以不再多创建云主机…

打卡--MySQL8.0 二 (用户权限管理)

一、mysql8修改了安全规则&#xff0c;不能像mysql5.7 一次性创建用户并授权&#xff0c;需要分批创建。 1、注意在MySQL8.0版本中创建用户一定要在配置文件中增加如下内容&#xff0c;来兼容旧的程序运行。 default_authentication_pluginmysql_native_password 2、创建用户…

LM2904DT运算放大器中文资料规格书PDF数据手册引脚图参数图片功能概述

产品概述&#xff1a; 该电路由两个独立的高增益运算放大器&#xff08;运算放大器&#xff09;组成&#xff0c;内部实现了频率补偿。它们专为汽车和工业控制系统而设计。该电路采用单电源供电&#xff0c;工作电压范围很广。低功耗与电源电压的大小无关。 应用领域包括传感…

【力扣 - 和为K的子数组】

题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2 示例 2&#xff1a; 输入&#xff1a;num…

ElementUI两个小坑

1.form表单绑定的是一个对象&#xff0c;表单里的一个输入项是对象的一个属性之一&#xff0c;修改输入项&#xff0c;表单没刷新的问题&#xff0c; <el-form :model"formData" :rules"rules" ref"editForm" class"demo-ruleForm"…

【机器学习】机器学习创建算法第1篇:机器学习算法课程定位、目标【附代码文档】

机器学习&#xff08;算法篇&#xff09;完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;机器学习算法课程定位、目标&#xff0c;K-近邻算法&#xff0c;1.1 K-近邻算法简介&#xff0c;1.2 k近邻算法api初步使用定位,目标,学习目标,1 什么是K-近邻算法,…

Java旋转矩阵

题目&#xff1a; 给你一幅由 N N 矩阵表示的图像&#xff0c;其中每个像素的大小为 4 字节。请你设计一种算法&#xff0c;将图像旋转 90 度。 不占用额外内存空间能否做到&#xff1f; 示例 1: 给定 matrix [ [1,2,3], [4,5,6], [7,8,9] ], 原地旋转输入矩阵&…

山姆・阿尔特曼重返OpenAI董事会;Car-GPT:LLMs能否最终实现自动驾驶?

&#x1f989; AI新闻 &#x1f680; 山姆・阿尔特曼重返OpenAI董事会 摘要&#xff1a;经历长达数月的审查后&#xff0c;山姆・阿尔特曼已重返OpenAI董事会&#xff0c;并作为返回条件之一&#xff0c;OpenAI还新增了三名外部女性董事会成员。这标志着公司正努力摆脱去年11…

开源模型应用落地-业务优化篇(八)

一、前言 在之前的学习中&#xff0c;我相信您已经学会了一些优化技巧&#xff0c;比如分布式锁、线程池优化、请求排队、服务实例扩容和消息解耦等等。现在&#xff0c;我要给您介绍最后一篇业务优化的内容了。这个优化方法是通过定时统计问题的请求频率&#xff0c;然后将一些…

交叉编译x264 zlib ffmpeg以及OpenCV等 以及解决交叉编译OpenCV时ffmpeg始终为NO的问题

文章目录 环境编译流程nasm编译x264编译zlib编译libJPEG编译libPNG编译libtiff编译 FFmpeg编译OpenCV编译问题1解决方案 问题2解决方案 总结 环境 系统&#xff1a;Ubutu 18.04交叉编译链&#xff1a;gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu 我的路径/opt/toolch…

【Flutter】报错Target of URI doesn‘t exist ‘package:flutter/material.dart‘

运行别人项目 包无法导入报错&#xff1a;Target of URI doesn’t exist ‘package:flutter/material.dart’ 解决方法 flutter packages get成功 不会报错

php CI框架异常报错通过钉钉自定义机器人发送

php CI框架异常报错通过钉钉自定义机器人发送 文章目录 php CI框架异常报错通过钉钉自定义机器人发送前言一、封装一个异常监测二、封装好钉钉信息发送总结 前言 我们在项目开发中&#xff0c;经常会遇到自己测试接口没问题&#xff0c;上线之后就会测出各种问题&#xff0c;主…

K8s — PVC|PV Terminating State

在本文中&#xff0c;我们将讨论PV和PVC一直Terminating的状态。 何时会Terminting? 在以下情况下&#xff0c;资源将处于Terminating状态。 在删除Bounded 状态的PVC之前&#xff0c;删除了对应的PV&#xff0c;PV在删除后是Terminting状态。删除PVC时&#xff0c;仍有引用…

python向多个用户发送文字、图片内容邮件和excel附件

话不多说&#xff0c;直接上代码&#xff0c;需要把发件里面的smtp_info替换为自己的信息&#xff0c;其中password是指邮箱在开通POP/SMTP功能后获取的授权码&#xff01; import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import M…

案例分析篇05:数据库设计相关28个考点(9~16)(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12601310.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…