C++ -4- 类和对象(下)

news2024/10/5 19:19:24

文章目录

  • 1.初始化列表
    • 什么是初始化列表?
    • 初始化列表的 意义及使用
  • 2.explicit关键字
    • 单参数构造函数(C++98)
    • 多参数的构造函数(C++11)(了解)
  • 3.static静态成员
    • 静态成员变量与静态成员函数
      • 静态成员变量
      • 静态成员函数
  • 4.匿名对象
  • 5.友元
    • 友元函数
    • 友元类
  • 6.内部类(C++很少用)
  • 7.拷贝对象时的一些编译器优化

1.初始化列表

什么是初始化列表?

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

例如:

class Date
{
public:
	Date(int year, int month, int day)
    	 : _year(year)//以冒号开始
     	, _month(month)//逗号分隔
     	, _day(day)//括号中为初始值
 		{}
private:
	int _year;
	int _month;
	int _day;
};

初始化列表的 意义及使用

在这里插入图片描述
在这里插入图片描述
(之所以没有默认生成构造函数是因为——默认生成的构造函数对内置类型不处理,但const 变量只有一次被定义的机会,必须要初始化)

  1. 不管哪个对象调用构造函数,初始化列表是它所有成员变量定义的地方
  2. 不管是否在初始化列表里有写,编译器每个变量都会在初始化列表被初始化
  3. 如果 const 变量有缺省值,只有当其他任何地方都没有给初始化值的时候才会用这个缺省值,即没给值才用缺省值
  • 注意:
  1. 每个成员只能初始化 一次
  2. 三类 必须初始化 的类型:
    • const
    • &引用
    • 没有默认构造函数的自定义类型
class Round
{
public:
	Round(int a)//这个不是默认构造函数,默认构造函数时不传参的!!
		:_a(a)
	{}

private:
	int _a;
};

class Bottle
{
public:
	Bottle(int a, int ref)
		:_rd(a)
		, _b(ref)
		, _n(13)
	{}

private:
	Round _rd;  // 没有默认构造函数
	int& _b;  // 引用
	const int _n; // const 
};

  1. 初始化的顺序是类中成员变量定义的顺序
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();
}

output:-1  随机值
  1. 建议尽量使用初始化列表

2.explicit关键字

单参数构造函数(C++98)

分析一段代码:

class A
{
public:
	A(int a)//单参数构造函数
		:_a1(a)
	{
		cout << "A(int a)" << endl;
	}

	A(const A& aa)//拷贝构造函数
		:_a1(aa._a1)
	{
		cout << "A(const A& aa)" << endl;
	}

private:
	int _a1;
	int _a2;
};

void Testexplicit()
{
	A aa1(1);
	A aa2 = 1;

	A& variable = 13;
    const A& variable = 13;
}

int main()
{
	Testexplicit();
	return 0;
}

在这里插入图片描述

🔊 explicit 不允许隐式类型转换:
在这里插入图片描述

多参数的构造函数(C++11)(了解)

class A
{
public:
	A(int a1, int a2)//多参数构造函数
		:_a1(a1)
		, _a2(a2)
	{}

private:
	int _a1;
	int _a2;
};

void Testexplicit()
{
	A aa3(1, 2);
	A aa4 = { 1,2 };
}

3.static静态成员

  • 如何统计 类的对象的个数

基本思路:创建 类的对象一定回去调用 构造函数 或者 拷贝构造函数

  1. 定义全局变量统计个数?
  • 代码:
int count = 0;
class A
{
public:
	A()//构造函数
	{
		++count;
	}
	A(const A& aa)//拷贝构造函数
	{
		++count;
	}

private:
	int _a1;
	int _a2;
};

void TestStatic()
{
	A a1, a2, a3, a4;
	cout << count << endl;
}
  • 问题:
  • 变量名冲突

报错:变量名 count 与 std 库发生冲突

error C2872: “count”: 不明确的符号
message : 可能是“int count”或 “iterator_traits<_Iter>::difference_type std::count(const _InIt,const _InIt,const _Ty &)”

所以,最好不要全局展开std

  • 容易出纰漏
    在这里插入图片描述

静态成员变量与静态成员函数

静态成员变量

  1. ✅静态成员变量:属于所有对象
  • 静态成员变量的声明和初始化:
class A
{
	static int count;//声明
};
int A::count = 0;//定义初始化

注意:静态成员变量声明处不能给缺省值,缺省值时给构造函数初始化用的,作用于非静态成员变量

  • 静态成员变量的访问:(以上述代码为例)

①当 静态成员变量 是 public

void TestStatic()
{
	A a1;
	a1.count;
	A::count;
	A* ptr = nullptr;  
	ptr->count;
}
  • 对象.count:A a1;a1.count;——创建对象,通过对象访问成员变量
  • A::count;
  • A* ptr = nullptr; ptr->count;

② 通过写函数访问

class A
{
public:
	A()//构造函数
	{
		++count;
	}
	A(const A& aa)//拷贝构造函数
	{
		++count;
	}

	int Getcount()
	{
		return count;
	}

private:
	int _a1;
	int _a2;

	static int count;//声明
};

int A::count = 0;//定义初始化

void TestStatic()
{
	A a1;
	cout << a1.Getcount() << endl;
}

静态成员函数

void TestStatic()
{
	A a1;
	cout << a1.Getcount() << endl;
}

👆为了调用这个函数专门要创建一个对象?→如何改进?→『 静态成员函数

  • 什么是 静态成员函数:(示例)
static int Getcount()
{
	return count;
}
  • 如何调用静态成员函数:
    A::Getcount();

(完整示例:↓)

class A
{
public:
	A()//构造函数
	{
		++count;
	}
	A(const A& aa)//拷贝构造函数
	{
		++count;
	}

	static int Getcount()
	{
		return count;
	}

private:
	int _a1;
	int _a2;

	static int count;//声明
};

int A::count = 0;//定义初始化

void TestStatic()
{
	A array[13];
	cout << A::Getcount() << endl;
}

ps.A array[13]; 自定义类型的数组,会自动调用13次构造函数。

  • 静态函数变量的特点:
    静态成员函数没有 this 指针,因此 不能访问非静态成员

4.匿名对象

  • 什么是匿名对象:
class A{};
A();//匿名对象
  • 匿名对象的特点:生命周期只在这一行

ps.临时变量和匿名对象都具有 常性


5.友元

友元分为 友元函数友元类,由于友元 破坏了封装 ,建议能不用就不用。

友元函数

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

示例:

class Date
{
public:
	//流插入
	//函数声明
	friend void operator<<(ostream& out, const Date& d);
	
private:
	int _year;
	int _month;
	int _day;
};

//函数定义
void operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	//友元函数可以直接访问类的私有成员
}

//函数调用:
cout << d1; 👉 operator<<(cout,d1);

注意:

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

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。 友元关系是单向的,不具有交换性。

在这里插入图片描述


6.内部类(C++很少用)

  • 概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个 独立(空间独立)的类,它不属于外部类!
  • 注意:内部类就是外部类的友元类,但是外部类不是内部类的友元。
  • 特性:
    1. 内部类可以定义在外部类的public、protected、private都是可以的。
    2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
    3. sizeof(外部类)=外部类,和内部类没有任何关系。内部类是独立的!

内部类可以看作是外部类的友元类,只是受外部类的类域限制。

class A
{
public:
	class B //内部类
	{
	public:
		void foo(const A& a)
		{
			cout << k << endl;
			cout << a.h << endl;
		}
	};


private:
	static int k;
	int h;
};

int A::k = 1;
int main()
{
	A::B b;//类B受外部类A的类域限制
	b.foo(A());
	return 0;
}

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

1. 构造+拷贝 → 优化为直接构造
当构造和拷贝都在一个表达式里时才能优化:

  • 不在一个表达式:
    在这里插入图片描述

  • 在一个表达式:
    在这里插入图片描述

2. 传引用传参 → 不优化,没有拷贝

3. 传值返回 → 不优化(如下代码,构造和拷贝不能结合起来)

A func()
{
	A aa;//构造   “构造”
	return aa;//返回一份临时拷贝 “拷贝”
}

4.返回值接收:拷贝+拷贝 → 优化成一个拷贝

class A{};

A func()
{
	A aa;//构造   “构造”
	return aa;//返回一份临时拷贝 “拷贝”
}

int main()
{
	/*func(A());*/

	A aa1 = func();//拷贝接收
	//func()“拷贝”+aa1"拷贝构造" → “拷贝”+“拷贝”

	//如果写成:
	A aa2;
	aa2 = func();//这样写不优化
	return 0;
}

5. 返回匿名对象

class A{};

A func()
{
	return A();
}

构造匿名对象 A() → “构造”
返回一个自定义对象,生成一份临时拷贝 → “拷贝”
构造+拷贝 → 优化为直接构造

sum.提高效率:
1.接收返回值对象,尽量用拷贝接收(4.)
2.返回值尽量用匿名对象(5.)
3.传参尽量用引用(2.)


END

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

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

相关文章

Java并发(三)----创建线程的三种方式及查看进程线程

一、直接使用 Thread // 创建线程对象 Thread t new Thread() {public void run() {// 要执行的任务} }; // 启动线程 t.start(); 例如&#xff1a; // 构造方法的参数是给线程指定名字&#xff0c;推荐 Thread t1 new Thread("t1") {Override// run 方法内实现…

Codeforces Round 864 (Div. 2)(A~D)

A. Li Hua and Maze 给出两个不相邻的点&#xff0c;最少需要堵上几个方格&#xff0c;才能使得两个方格之间不能互相到达。 思路&#xff1a;显然&#xff0c;对于不邻任何边界的方格来说&#xff0c;最少需要的是4&#xff0c;即上下左右都堵上&#xff1b;邻一个边界就-1&a…

Python樱花树

文章目录 前言一、Turtle基础1.1 Turtle画板1.2 Turtle画笔1.3 Turtle画图1.4 Turtle填色1.5 Turtle写字 二、Python樱花树2.1 樱花类2.2 樱花树2.3 主函数2.4 程序分析2.5 樱花林 尾声 前言 粉色系最爱&#xff01;Python樱花树等你获取~ 哈喽小伙伴们好久不见啦&#xff0c;…

几何感知Transformer用于3D原子系统建模

基于机器学习的方法在预测分子能量和性质方面表现出很强的能力。分子能量至少与原子、键、键角、扭转角和非键原子对有关。以前的Transformer模型只使用原子作为输入&#xff0c;缺乏对上述因素的显式建模。为了减轻这种限制&#xff0c;作者提出了Moleformer&#xff0c;这是一…

ChatGPT课程送账号啦,让你成为新生代AI程序员

ChatGPT能帮助程序员 解决哪些具体问题&#xff1f; 程序员在日常工作中可能会遇到各种各样的问题&#xff0c;如语法错误、逻辑问题、性能问题等等。 不同业务场景的问题&#xff0c;都可以利用ChatGPT获取各自场景下的知识&#xff0c;并使用ChatGPT提供的代码示例和问题解…

S32K3系列单片学习LPSPI是什么

前言 通过前面的学习&#xff0c;已经可以实现最基础的引脚配置功能了&#xff0c;并实现了点亮LED的程序。下面将记录一下&#xff0c;S32K3的SPI模块的配置方法&#xff0c;以及注意事项。 一、LPSPI介绍 **LPSPI:LOW POWER Serial Peripheral Interface**1.概述 所有LPS…

Unity3d数字化看板-多关节机器人运动控制

特殊&#xff1a;机器人多关节跟随运动 机械手运动控制主要是关节的旋转&#xff0c;通过控制多个关节的角度&#xff0c;实现对机械手的同步控制 机械手运动控制&#xff0c;可以分解为多个关节的运动&#xff0c;下一关节是跟随在上一关节运动&#xff0c;在处理模型的时候…

小案例CSS

代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge"> <meta name"viewport" content"widthde…

一个基于 go 实现的轻量级任务调度框架

github 地址&#xff1a;GitHub - memory-overflow/light-task-scheduler: 一个go语言的轻量级的快速实现任务调度的框架&#xff0c;并且支持有状态任务的持久化&#xff0c;并发控制和超时控制。 框架的设计思想和背景 业务后台开发&#xff0c;经常会遇到很多并发低&#…

QT笔记——属性栏之QtPropertyBrowser下载配置

我们常常看到Qt Designer如下图&#xff0c;属性栏 环境&#xff1a;vs2019 qt 5.12.2 QtPropertyBrowser 下面我将介绍如何去下载和安装配置 QtPropertyBrowser&#xff0c;使用的是.dll和.lib 第一种方式&#xff1a;编译qt4 源码的方式 然后修改为qt5 的形式 第一步&am…

Ext JS 4实现合并行单元格

目录 文件 最后由 oscar999 在 几秒前 编辑 有一位朋友咨询了一个问题: 在Ext JS 4中, 如何合并行的单元格, 已经选取的时候只能选择某一列, 期望的效果如下: 在Ext JS 中, 合并表头的列有现成方案, 但是合并行单元格不是extjs的现有功能,这个需要底层扩展, 也就是使…

云原生(docker+k8s+阿里云)-Docker

Gitee-Kubernetes学习 kubectl备忘清单 k8s官方文档-task [云原生-kubectl命令详解] ingress详解 ingress官方文档 云原生-语雀-架构师第一课 从Docker到Kubernetes进阶-社区 云计算学习路线-阿里云大学 如上图&#xff0c;服务器有公网ip和私网ip&#xff0c;公网ip是外部访问…

AWT-对话框——Dialog以及其子类FileDialog

Dialog: Dialog时Window类的子类&#xff0c;时一个容器类&#xff0c;属于特殊组件。对话框是可以独立存在的顶级窗口&#xff0c;因此用法与普通窗口的用法几乎完全一样&#xff0c;但是使用对话框需要注意以下几点&#xff1a; 对话框通常依赖于其它窗口&#xff0c;就是通…

分布式系统通信中使用安全套接字(SSL/TSL)

协商加密和认证算法 SSL的设计&#xff0c;可以在链接的两端初始化握手通信时&#xff0c;在进程间协商加密和认证的算法。 因此可能出现在通信双方没有足够的公共算法导致链接尝试失败的情况。 自举安全通信 通过混合协议建立安全通道。 使未加密的通信进行初始化交换&#xf…

【论文笔记】SwinIR: Image Restoration Using Swin Transformer

声明 不定期更新自己精度论文&#xff0c;通俗易懂&#xff0c;初级小白也可以理解 涉及范围&#xff1a;深度学习方向&#xff0c;包括 CV、NLP、Data Fusion、Digital Twin 论文标题&#xff1a;SwinIR: Image Restoration Using Swin Transformer 论文链接&#xff1a;http…

IDAPython入门基础语法

文章目录 参考文章IDAPython简介常用函数获取界面地址的函数数值获取函数数值判断函数patch操作函数去除花指令实例 参考文章 IDAPython入门教程 基于IDA7.5_Python3 第一讲 简介与地址获取 IDAPython简介 IDAPython拥有强大的功能,在使用IDA分析程序时非常有用,可以简化许多…

队列的实现

队列 简介 队列是一种线性表的特殊形式&#xff0c;特殊之处在于它只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在表的后端&#xff08;rear&#xff09;进行插入操作&#xff0c;和栈一样&#xff0c;队列是一种操作受限制的线性表。进行插入操…

信息安全复习五:数据加密标准(DES)

一、本章梗概 1.主要内容&#xff1a;分组密码、分组密码用到的关键技术和结构、对称密钥密码典型算法DES 2.思考问题&#xff1a; ①按照明文被处理的形式&#xff0c;DES属于标准的什么密码 ②根据密钥的使用数量&#xff0c;DES属于标准的什么密码 3.内容回顾&#xff1a; …

力扣sql中等篇练习(十二)

力扣sql中等篇练习(十二) 1 产品销售分析 ||| 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT s1.product_id,s1.first_year,s2.quantity,s2.price FROM (SELECT product_id,Min(year) first_yearF…

基于趋动云的chatGLM-6B模型的部署

首先根据官方示例教程&#xff0c;学会怎么创建项目&#xff0c;怎么使用数据&#xff0c;怎么进入开发环境&#xff0c;以及了解最重要的2个环境变量&#xff1a; 这个是进入开发环境以后的代码目录 $GEMINI_CODE 这个是引用数据集后&#xff0c;数据集存放的路径 $GEMINI_DA…