C++——类和对象(下)

news2024/11/24 4:33:50

文章目录

  • 一、再探构造函数——初始化列表
  • 二、 类型转换
  • 三、static成员
    • 静态成员变量
    • 静态成员函数
  • 四、 友元
    • 友元函数
    • 友元类
  • 五、内部类
  • 六、匿名对象

一、再探构造函数——初始化列表

之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表。

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

class Date
{
public:
	//初始化列表
	Date(int year)
		:_year(year),_month(12),_day(day + 12)
	{}
private:
	int _year;
	int _month;
	int _day;
};
  • 每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地⽅。
  • 引⽤成员变量,const成员变量,没有默认构造函数的类类型成员,必须放在初始化列表位置进⾏初始化,否则会编译报错。
class A
{
private:
	A(int n)
	{
		val = n;
	}
public:
	int val;
};


class Date
{
public:
	//初始化列表
	Date(int year, int month, int day)
		//定义
		:_year(year), _month(month), _day(day)
	{}
private:
	//声明
	int _year;
	int _month;
	int _day;
	const int _a;//error
	int& _b;//error
	A _c;//error
};

在这里插入图片描述

  • 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆关。建议声明顺序和初始化列表顺序保持⼀致。

  • C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的成员使⽤的。

#include <iostream>
using namespace std;

class Date
{
public:
	//初始化列表
	Date(int year, int month)
		//定义
		:_year(year), _month(month)
	{}
	void print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	//声明
	int _year;
	int _month;
	int _day = 16;
};

int main()
{
	Date d1(2024, 7);
	d1.print();
	return 0;
}

在这里插入图片描述
总结:尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表。
在这里插入图片描述

二、 类型转换

C++ 允许从内置类型(如 int, float 等)到类类型的隐式类型转换,但这要求类中必须定义一个接受相应内置类型参数的构造函数。
为了防止不必要的隐式转换,可以在构造函数声明前使用 explicit 关键字,这样编译器就不会自动执行这类转换,从而避免潜在的错误和混淆。

#include <iostream>
using namespace std;

class A
{
public:
	A(int n)
	{
		val = n;
	}
	A(int n, int m)
	{
		val = n;
		exc = m;
	}
private:
	int val;
	int exc;
};

int main()
{
	//1构造一个A的临时对象,再用这个临时对象拷⻉构造a
	A a = 1;
	// C++11之后才支持多参数转化
	A aa3 = { 2,2 };
	return 0;
}

加上explicit之后,编译就会报错,不能隐式类型转换了

#include <iostream>
using namespace std;

class A
{
public:
	explicit A(int n)
	{
		val = n;
	}
	explicit A(int n, int m)
	{
		val = n;
		exc = m;
	}
private:
	int val;
	int exc;
};

int main()
{
	//1构造一个A的临时对象,再用这个临时对象拷⻉构造a
	A a = 1;
	// C++11之后才支持多参数转化
	A aa3 = { 2,2 };
	return 0;
}

在这里插入图片描述

三、static成员

静态成员变量

⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。

  • 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。
#include <iostream>
using namespace std;

class A
{
public:
	//A()
	//	// error C2438: “exc”: 无法通过构造函数初始化静态类数据
	//	:val(1),exc(2)
	//{
	//	
	//}
	void print()
	{
		cout << val << " " << exc << endl;
	}
private:
	int val;
	//类里面声明
	static int exc;
};

//类外面初始化
int A::exc = 1;

int main()
{
	A a;
	a.print();
	return 0;
}

静态成员函数

⽤static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。

  • 静态成员函数中可以访问其他的静态成员,但是不能访问⾮静态的,因为没有this指针。
  • ⾮静态的成员函数,可以访问任意的静态成员变量和静态成员函数。
#include <iostream>
using namespace std;

class A
{
public:
	static void PK();
	void print()
	{
		cout <<  exc << endl;
	}
private:
	//类里面声明
	static int exc;
};

//类外面初始化
int A::exc = 1;

void A::PK()
{
	//error C2597: 对非静态成员“A::val”的非法引用
	//val = 1;
	cout << "666" << endl;
}

int main()
{
	A a;
	a.print();
	a.PK();
	A::PK();
	return 0;
}

在这里插入图片描述

注意:

突破类域就可以访问静态成员,可以通过类名::静态成员或者对象. 静态成员来访问静态成员变量和静态成员函数。

静态成员也是类的成员,受public、protected、private访问限定符的限制。

静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不⾛构造函数初始化列表。

就好比这个题目:求1+2+3+…+n

class Sum
{
public:
    Sum()
    {
        num++;
        k += num;
    }
    static int GetK()
    {
        return k;
    }
private:
    static int num;
    static int k;
};

int Sum::num = 0;
int Sum::k = 0;

class Solution
{
public:
    int Sum_Solution(int n)
    {
        Sum a[n];
        return Sum::GetK();
    }
};

四、 友元

友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类。
实现方法:在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。

友元函数

  • 外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。
  • 友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制。
  • ⼀个函数可以是多个类的友元函数。
#include <iostream>
using namespace std;

class A
{
public:
	//友元声明
	friend void PK(A& ra);
	void print()
	{
		cout << _a << endl;
	}
private:
	int _a = 1;
};

void PK(A& ra)
{
	cout << ra._a << endl;
}

int main()
{
	A a;
	PK(a);
	a.print();
	return 0;
}

在这里插入图片描述

友元类

  • 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。
  • 友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。
  • 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元。
#include <iostream>
using namespace std;

class A
{
public:
	//友元声明
	friend class B;
	void print()
	{
		cout << _a << endl;
	}
private:
	int _a = 1;
};

class B
{
public:
	void print(A& ra)
	{
		ra._a = 3;
		ra.print();
		cout << _b << endl;
	}
private:
	int _b = 2;
};

int main()
{
	A a;
	B b;
	b.print(a);
	return 0;
}

在这里插入图片描述

注意:友元虽然有时提供了便利,但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤。

五、内部类

如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。

内部类是⼀个独⽴的类,跟定义在全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。

内部类默认是外部类的友元类。

内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类,如果放private/protected位置,那么A类就是B类的专属内部类,其他地⽅都⽤不了。

那么前面的那道题就可以这么写:

class Solution
{
public:
    int Sum_Solution(int n)
    {
        Sum a[n];
        return k;
    }
    static int num;
    static int k;

private:
    class Sum
    {
    public:
        Sum()
        {
            num++;
            k += num;
        }
        static int GetK()
        {
            return k;
        }
   
    };
};
int Solution::num = 0;
int Solution::k = 0;

六、匿名对象

⽤类型(实参)定义出来的对象叫做匿名对象,相⽐之前我们定义的类型对象名(实参)定义出来的叫有名对象。

匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象。

使用匿名对象的优点在于它可以帮助减少代码的冗余和复杂性,特别是在对象只是用一次的情况下。由于没有持久的引用,匿名对象在使用后会被自动清理,有助于节省内存资源。

#include <iostream>
using namespace std;

class A
{
public:
	A(int v = 1)
		:val(v)
	{}
	~A()
	{
		cout << "~A()->"  << val << endl;
	}
	void print()
	{
		cout << val << endl;
	}
private:
	int val;
};

int main()
{
	A a;
	// 不能这么定义对象,因为编译器无法识别下面是⼀个函数声明,还是对象定义
	//warning C4930: “A aa1(void)”: 未调用原型函数(是否是有意用变量定义的?)
	//A aa1();
	// 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,
	// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函
	A(2);
	A(3);
	A aa(4);
	//无需命名,直接使用类的函数,非常方便
	A().print();
	return 0;
}

在这里插入图片描述

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

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

相关文章

【读点论文】ASAM: Boosting Segment Anything Model with Adversarial Tuning,对抗学习提升性能

ASAM: Boosting Segment Anything Model with Adversarial Tuning Abstract 在不断发展的计算机视觉领域&#xff0c;基础模型已成为关键工具&#xff0c;对各种任务表现出卓越的适应性。其中&#xff0c;Meta AI 的 Segment Anything Model (SAM) 在图像分割方面表现突出。然…

第十一届MathorCup高校数学建模挑战赛-C题:海底数据中心的散热优化设计(续)(附MATLAB代码实现)

目录 5.3 问题三的求解 5.3.1 数据分析 5.3.2 数据处理 5.3.4 得出结论 5.4 问题四的求解 5.4.1 数据分析 5.4.2 算法分析 5.5 问题五的求解 六、模型评价与推广 6.1 模型的优点 6.2 模型的缺点 6.3 模型的推广 七、参考文献 代码实现 8.1 图 4 的代码 8.2 图 5 的代码 8.3 图…

旗晟巡检机器人的应用场景有哪些?

巡检机器人作为现代科技的杰出成果&#xff0c;已广泛应用于各个关键场景。从危险的工业现场到至关重要的基础设施&#xff0c;它们的身影无处不在。它们以精准、高效、不知疲倦的特性&#xff0c;担当起保障生产、守护安全的重任&#xff0c;为行业发展注入新的活力。那么&…

VMware安装CentOS 7

在虚拟机中安装无论是Windows还是Linux其实都差不多&#xff0c;主要还是需要熟悉VMware的使用&#xff0c;多新增几次就熟悉了&#xff0c;可以反复删除再新增去练习… 如下是安装CentOS 7 安装过程&#xff1a; VMare Workstation 16 PRO 中安装CentOS 7 CentOS 7 下载推荐…

PTA - 嵌套列表求和

使用递归函数对嵌套列表求和 函数接口定义&#xff1a; def sumtree(L) L是输入的嵌套列表。 裁判测试程序样例&#xff1a; /* 请在这里填写答案 */L eval(input()) print(sumtree(L)) # 调用函数 输入样例&#xff1a; 在这里给出一组输入。例如&#xff1a; [1,[2…

数据结构-C语言-排序(1)

代码位置&#xff1a;test-c-2024: 对C语言习题代码的练习 (gitee.com) 一、前言&#xff1a; 1.1-排序定义&#xff1a; 排序就是将一组杂乱无章的数据按照一定的规律&#xff08;升序或降序&#xff09;组织起来。 1.2-排序分类&#xff1a; 常见的排序算法&#xff1a; 插…

业务终端动态分配IP-DHCP技术、DHCP中继技术

一、为什么需要DHCP? 1、许多设备(主机、无线WiFi终端等)需要动态地址的分配; 2、人工手工配置任务繁琐、容易出错,比如:IP地址冲突; 3、网络规模扩大、复杂度提高,网络配置越来越复杂,计算机的位置变化和数量超过可分配IP地址的数量,造成IP地址变法频繁以及IP地址…

【精品资料】大数据可视化平台数据治理方案(626页WORD)

引言&#xff1a;大数据可视化平台的数据治理方案是一个综合性的策略&#xff0c;旨在确保大数据的质量、安全性、可访问性和合规性&#xff0c;从而支持高效的数据分析和可视化过程。 方案介绍&#xff1a; 大数据可视化平台的数据治理方案是一个综合性的策略&#xff0c;旨在…

SimMIM:一个类BERT的计算机视觉的预训练框架

1、前言 呃…好久没有写博客了&#xff0c;主要是最近时间比较少。今天来做一期视频博客的内容。本文主要讲SimMIM&#xff0c;它是一个将计算机视觉&#xff08;图像&#xff09;进行自监督训练的框架。 原论文&#xff1a;SimMIM&#xff1a;用于掩码图像建模的简单框架 (a…

设计模式-UML类图

1.UML概述 UML-统一建模语言&#xff0c;用来设计软件的可视化建模语言&#xff1b; 1.1 UML分类 静态结构图&#xff1a;类图、对象图、组件图、部署图动态行为图&#xff1a;状态图、活动图、时序图、协作图、构件图等 类图&#xff1a;反应类与类结构之间的关系&#xff0…

【46 Pandas+Pyecharts | 当当网畅销图书榜单数据分析可视化】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 去除重复数据2.4 书名处理2.5 提取年份 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 作者图书数量分布3.2 图书出版年份…

2-36 基于matlab的流行学习算法程序

基于matlab的流行学习算法程序。通过GUI的形式将MDS、PCA、ISOMAP、LLE、Hessian LLE、Laplacian、Dissusion MAP、LTSA八种算法。程序以可视化界面进行展示&#xff0c;可直接调用进行分析。多种案例举例说明八种方法优劣&#xff0c;并且可设置自己数据进行分析。程序已调通&…

podman 替代 docker ? centos Stream 10 已经弃用docker,开始用podman了!

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

前端vue项目打镜像并拉取镜像包

前端vue项目打镜像并拉取镜像包 如图需要准备三部分的内容 1.前置要求 linux 环境 docker环境2.vue打包后的静态文件&#xff0c;需要自行打包 npm run build 打包后上传到服务器3.nginx配置&#xff08;default.conf文件配置&#xff09; server {listen 80;serve…

浅谈Visual Studio 2022

Visual Studio 2022&#xff08;VS2022&#xff09;提供了众多强大的功能和改进&#xff0c;旨在提高开发者的效率和体验。以下是一些关键功能的概述&#xff1a;12 64位支持&#xff1a;VS2022的64位版本不再受内存限制困扰&#xff0c;主devenv.exe进程不再局限于4GB&#xf…

SQL Server的视图

SQL Server的视图 一、基础 SQL 视图&#xff08;Views&#xff09;是一种虚拟表&#xff0c;是基于 SQL 查询结果生成的。这些虚拟表可以包含来自一个或多个表的数据&#xff0c;并且可以像表一样查询&#xff1b;视图是一个表中的数据经过某种筛选后的显示方式&#xff0c;或…

在 Linux 系统中安装MySQL 8.x(Ubuntu和CentOS)

文章目录 0. 前言1. 查看 Linux 的发行版本2. 在 Ubuntu 中安装MySQL 8.x2.1 更新包索引2.1.1 更改 Ubuntu 的镜像源2.1.2 更新软件包、升级软件包&#xff08;耗时可能较长&#xff09;2.1.3 可能遇到的问题 2.2 安装MySQL2.3 安全配置2.3.1 密码安全级别2.3.2 删除匿名用户2.…

昇思25天学习打卡营第25天|GAN图像生成

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) GAN图像生成 模型简介 生成式对抗网络(Generative Adversarial Networks&#xff0c;GAN)是一种生成式机器学习模型&#xff0c;是近年来复杂分布上无监督学习最具前景的方法之一。 GAN论文逐…

iOS——MRC与ARC以及自动释放池深入底层学习

MRC与ARC再回顾 在前面&#xff0c;我们简单学了MRC与ARC。MRC指手动内存管理&#xff0c;需要开发者使用retain、release等手动管理对象的引用计数&#xff0c;确保对象在必要时被释放。ARC指自动内存管理&#xff0c;由编译器自动管理对象的引用计数&#xff0c;开发者不需要…

SQL注入问题

一、什么是sql注入 public class TestSql {public static void main(String[] args) {Scanner inScanner new Scanner(System.in);System.out.println("请输入用户名");String username inScanner.nextLine();System.out.println("请输入密码");String …