[C++]类和对象(下)

news2024/10/7 8:22:23

一:再谈构造函数

1.1 构造函数体赋值

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

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

1.2 初始化列表

初始化列表:

成员变量的定义(初始化)是在初始化列表中进行的,而构造函数体中可以给成员变量进行赋值

格式:

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

特点:

1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

2. C++11 中内置类型成员变量在类中声明时可以给默认值,默认值就是在初始化列表中使用的

        在初始化列表中给_day初始化为123,其并没有使用成员变量声明时给的缺省值,而_year和_month使用的就是缺省值

2. 类中包含以下成员,必须放在初始化列表位置进行初始化:

  • &引用成员变量
  • const成员变量
  • 自定义类型成员(且该类没有默认构造函数时)

引用成员变量与const成员变量

        由于引用修饰的变量与const修饰的变量在定义的时候就必须进行初始化,若在函数体中给他们赋值,编译器会报错,因为此时是赋值不是初始化

成员变量的定义是在初始化列表中进行的,所以这两中变量只能在初始化列表中初始化

class Date
{
public:
	Date(int year, int month, int day,int aa,int &b)
		:_aa(aa)
		,_b(b)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
	const int _aa;
	int& _b;
};

函数体中的成员也可以在初始化列表中进行赋值,两者的使用并不冲突,甚至可以在初始化列表中直接初始化,再在函数体中赋值一遍,但是写两遍没有意义,只需要写一个就好了
 

class Date
{
public:
	Date(int year, int month, int day,int aa,int &b)
		:_aa(aa)
		,_b(b) 
		,_year(year)
		,_month(month)
		,_day(day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
	const int _aa;
	int& _b;
};

自定义类型成员(且该类没有默认构造函数时)

当类中存在自定义类型变量时,编译器会自动调用其默认构造函数,若不存在默认构造函数就会报错,解决报错的方法有两个:

方法一: 补充默认构造函数

方法二: 在初始化列表调用多参数构造函数初始化自定义类型变量

class Time
{
public:
	Time(int hour, int min)
	{
		_hour = hour;
		_min = min;
	}
private:
	int _hour;
	int _min;
};
class Date
{
public:
	Date(int year, int month, int day,int aa,int &b)
		:_t(1,2)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};

3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。

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

1.3 explicit关键字 

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

再许多情景这个类型转换是十分方便的,例如:

 如果在一些情况下不希望有类型转换,可以在构造函数的前面加一个explicit,用explicit修饰构造函数,将会禁止构造函数的隐式转换。

二:static成员 

2.1 概念

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

2.2 特点

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

面试题:实现一个类,计算程序中创建出了多少个类对象

class A
{
public:
	A() { ++_scount; }  //构造函数
	A(const A & t) { ++_scount; } //拷贝构造
	~A() { --_scount; } //析构
	static int GetACount() { return _scount; } //使用静态成员函数访问静态成员
private:
	static int _scount;
};
int A::_scount = 0;
void TestA()
{
	cout << A::GetACount() << endl;
	A a1, a2;
	A a3(a1);
	cout << A::GetACount() << endl;
}

三: 友元

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

3.1 友元函数

        在类外如果一个函数想要访问类中的私有成员,除了将类的成员改为共有的方法外,友元函数也可以解决这个问题

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

class A
{
	friend int func(A& a);
private:
	 int _aa;
};
int func(A& a)
{
	int b = a._aa;
    return b;
}

说明:

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

3.2 友元类

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

class Date
{
	friend class Time; //Time类是Date类的友元类,则Time类中可以访问Date类中的私有成员
public:
	Date(int year=2024, int month=2, int day=6)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
class Time
{
public:
	Time(int hour = 10, int min = 9)
	{
		_hour = hour;
		_min = min;
	}
	void Print()
	{
		cout << d._year << " " << d._month << " " << d._day << endl;
	}
private:
	int _hour;
	int _min;
	Date d;
};
int main()
{
	Time t;
	t.Print();
	return 0;
}

注意:

1. 友元关系是单向的,不具有交换性

class Date
{
	friend class Time; //Time类是Date类的友元类,则Time类中可以访问Date类中的私有成员
public:
	Date(int year=2024, int month=2, int day=6)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//错误::Time类是Date类的友元类,则Time类中可以访问Date类中的私有成员,但是Date类不能访问Time类的成员,除非Date也是Time的友元类
	void Print()
	{
		cout << t._year << " " << t._month << " " << dt_day << endl; //error
	}
private:
	int _year;
	int _month;
	int _day;
	Time t;
};
class Time
{
public:
	Time(int hour = 10, int min = 9)
	{
		_hour = hour;
		_min = min;
	}
	void Print()
	{
		cout << d._year << " " << d._month << " " << d._day << endl;
	}
private:
	int _hour;
	int _min;
	Date d;
};

2.友元关系不能传递,如果C是B的友元, B是A的友元,则不能说明C时A的友元


3.友元关系不能继承

四.内部类

概念:

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

特性:

1. sizeof(外部类)=外部类,和内部类没有任何关系

因为类只是声明,内部类没有定义出来,sizeof(A)的大小不算内部类

2.内部类是外部类的友元类(外部类不是内部类的友元类)

class A
{
public:
	class B
	{
	public:
		//内部类可以访问外部类的私有成员,但外部类不能访问内部类的私有成员
		void func(A& a)
		{
			cout << a._aa << a._bb << endl;
		}
	private:
		int a;
	};
private:
	int _aa;
	int _bb;
};

3.内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

class A
{
private:
	static int k;
	int h;
public:
	class B 
	{
	public:
		void func(const A& a)
		{
			cout << k << endl;//OK
			cout << a.h << endl;//OK
		}
	};
};
int A::k = 1

五:匿名对象

定义方法: 类名(参数)

class A
{
public:
	A(int a=1,int b=2)
		:_aa(a)
		,_bb(b)
	{}
private:
	int _aa;
	int _bb;
};
int main()
{
	//有名对象
	A a1();
	A a2(10,20);
	//匿名对象
	A();
	A(10, 20);
}

 注意:

  •  匿名对象的声明周期只有定义的这一行

  • 匿名对象常用情景:

        当构造一个函数仅仅只为了调用其成员函数时,可以利用匿名对象调用,这样调用完成后到下一行匿名对象就销毁了

class A
{
public:
	//构造函数
	A(int a = 1, int b = 2)
		:_aa(a)
		,_bb(b)
	{}
	void func()
	{
		cout << "func" << endl;
	}
private:
	int _aa;
	int _bb;
};
int main()
{
	//普通方法:
	A a1;
	a1.func();

	//匿名对象
	A().func();
	return 0;
}

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

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

相关文章

Rust开发WASM,浏览器运行WASM

首先需要安装wasm-pack cargo install wasm-pack 使用cargo创建工程 cargo new --lib mywasm 编辑Cargo.toml文件&#xff0c;修改lib的类型为cdylib&#xff0c;并且添加依赖wasm-bindgen [package] name "mywasm" version "0.1.0" edition "…

精酿啤酒:使用全麦芽酿造的优点与挑战

全麦芽酿造是指使用全部麦芽而非仅使用部分麦芽进行啤酒酿造的过程。近年来&#xff0c;全麦芽酿造在啤酒行业中逐渐受到关注。对于Fendi Club啤酒来说&#xff0c;使用全麦芽酿造也带来了一些优点和挑战。 使用全麦芽酿造的优点首先体现在啤酒的口感和风味上。全麦芽含有更多的…

正点原子--STM32通用定时器学习笔记(2)

1. 通用定时器输入捕获部分框图介绍 捕获/比较通道的输入部分&#xff08;通道1&#xff09; 输入通道映射CC1S[1:0]→采样频率CKD[1:0]→滤波方式IC1F[3:0]→边沿检测方式CC1P→捕获分频ICPS[1:0]→使能捕获CC1E 输入部分对相应的TIx输入信号采样&#xff0c;并产生一个滤波后…

论文阅读-Transformer-based language models for software vulnerability detection

「分享了一批文献给你&#xff0c;请您通过浏览器打开 https://www.ivysci.com/web/share/biblios/D2xqz52xQJ4RKceFXAFaDU/ 您还可以一键导入到 ivySCI 文献管理软件阅读&#xff0c;并在论文中引用 」 本文主旨&#xff1a;本文提出了一个系统的框架来利用基于Transformer的语…

【教学类-47-01】UIBOT+IDM下载儿童古诗+修改文件名

背景需求&#xff1a; 去年12月&#xff0c;我去了其他幼儿园参观&#xff0c;这是一个传统文化德育教育特色的学校&#xff0c;在“古典集市”展示活动中&#xff0c;小班中班大班孩子共同现场念诵《元日》《静夜思》包含了演唱版本和儿歌念诵版本。 我马上也要当班主任了&a…

【OpenVINO™】在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5 (下篇)

在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5 &#xff08;下篇&#xff09; 项目介绍 YOLOv5 是革命性的 "单阶段"对象检测模型的第五次迭代&#xff0c;旨在实时提供高速、高精度的结果&#xff0c;是世界上最受欢迎的视觉人工智能模型&#xff0c;代表了Ult…

单片机学习笔记---串口通信(1)

目录 通信的基本概念 通信的方式 1.按照数据传送的方式&#xff0c;可分为串行通信和并行通信。 1.1串行通信 1.2并行通信 2.按照通信的数据同步方式&#xff0c;又可以分为异步通信和同步通信。 2.1 异步通信 2.2同步通信 3.按照数据的传输方向&#xff0c;又可以分为…

【JAVA WEB】Web标签

目录 注释标签 标题标签 h1-h6 段落标签 换行标签 格式化标签 加粗&#xff1a;strong 标签和 b 标签 倾斜&#xff1a;em 标签和 i 标签 删除线&#xff1a; del 标签 和 s 标签 下划线&#xff1a;ins 标签 和 u 标签 图片标签&#xff1a;img 单标签 src属性&#…

零基础学Python之网络编程

1.什么是socket 官方定义&#xff1a; 套接字&#xff08;socket&#xff09;是一个抽象层&#xff0c;应用程序可以通过它发送或接收数据&#xff0c;可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中&#xff0c;并与网络中的其他应用…

外汇天眼:台中女老板扮演诈团「假币商」,诓134人投资吸金1.8亿

自从比特币问世以来&#xff0c;加密货币为金融领域带来极大的转变&#xff0c;而且随着区块链与各种技术发展&#xff0c;其影响力逐渐扩大&#xff0c;受到愈来愈多投资人重视&#xff0c;相关的金融商品与合约也愈来愈多元&#xff0c;更带起一波投资热潮。 然而&#xff0…

【开源】SpringBoot框架开发超市账单管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统设计3.1 总体设计3.2 前端设计3.3 后端设计在这里插入图片描述 四、系统展示五、核心代码5.1 查询供应商5.2 查询商品5.3 新增超市账单5.4 编辑超市账单5.5 查询超市账单 六、免责说明 一、摘要 1.1 项目介绍 基于…

thinkadmin的form.html表单例子

<style>textarea {width: 100%;height: 200px;padding: 10px;border: 1px solid #ccc

基于 GPU 渲染的高性能空间包围计算

空间包围检测在计算机图形学、虚拟仿真、工业生产等有着广泛的应用。 现代煤矿开采过程中&#xff0c;安全一直是最大的挑战之一。地质空间中存在诸多如瓦斯积聚、地质构造异常、水文条件不利等隐蔽致灾因素&#xff0c;一旦被触发&#xff0c;可能引发灾难性的后果。因此在安…

LeetCode 200:岛屿数量(图的简化版之网格结构上的BFS、DFS)

图的BFS和DFS 首先让我们回顾一下图的BFS和DFS遍历。可以看到这种BFS和DFS板子适用于图形状&#xff0c;或者说结构已经确定&#xff0c;即我们遍历的时候只需要从根节点从上往下遍历即可&#xff0c;不用考虑这个节点有几个叶子节点&#xff0c;是否会遍历到空节点等边界情况…

如果品牌刚刚开始,切入私域社群团购,快团团是最好的选择

如果品牌刚刚开始&#xff0c;切入私域社群团购&#xff0c;快团团是最好的选择&#xff0c;借力新渠道社群团购&#xff0c;快团团&#xff0c;成就你的新品牌&#xff0c; 社群团购平台本身就有大量的信任你平台的流量&#xff0c;这个流量基数是巨大的。 你要知道的是&…

【DDD】学习笔记-服务行为模型

如果将服务视为一种行为&#xff0c;就必然需要考虑客户端与服务之间的协作。服务行为的调用者可以认为是服务消费者&#xff08;Service Consumer&#xff09;&#xff0c;提供服务行为的对象则是服务提供者&#xff08;Service Provider&#xff09;。为了服务消费者能够发现…

C++ STL: vector使用及源码剖析

vector使用 vector定义 语句 作用 vector<int> a(n); 指定容器大小为n vector<int> a(n, x); 指定容器大小为n&#xff0c;并初始化所有元素为x vector<vector<int>> a(m, vector<int>(n)); m行n列的二维数组&#xff0c;可以直接…

游戏开发-会飞的小鸟(已完结,附源码)

游戏开发-会飞的小鸟&#xff08;已完结&#xff0c;附源码&#xff09; 你将学到的课程链接详细介绍 你将学到的 掌握Java编程的基本技能开发出自己的“会飞的小鸟”游戏对面向对象编程有深刻的理解学会运用常见算法和数据结构解决问题能够独立调试和优化自己的代码 课程链接…

(2)(2.14) SPL Satellite Telemetry

文章目录 前言 1 本地 Wi-Fi&#xff08;费用&#xff1a;30 美元以上&#xff0c;范围&#xff1a;室内&#xff09; 2 蜂窝电话&#xff08;费用&#xff1a;100 美元以上&#xff0c;范围&#xff1a;蜂窝电话覆盖区域&#xff09; 3 手机卫星&#xff08;费用&#xff…

Android.mk 语法详解

一.Android.mk简介 Android.mk 是Android 提供的一种makefile 文件,注意用来编译生成&#xff08;exe&#xff0c;so&#xff0c;a&#xff0c;jar&#xff0c;apk&#xff09;等文件。 二.Android.mk编写 分析一个最简单的Android.mk LOCAL_PATH : $(call my-dir) //定义了…