当前位置: 首页 > article >正文

“再探构造函数”(2)

文章目录

  • 一. 友元
    • ‘全局函数’作友元
    • ‘成员函数’作友元
    • ‘类‘作友元
  • 二. 内部类
  • 三. 匿名对象
  • 四. 对象拷贝时的编译器优化
  • 分析调用时的顺序

一. 友元

何时会用到友元呢?

当想让(类外面的某个函数/其它的类)访问 某个类里面的(私有或保护的)内容时,可以选择使用友元。

友元提供了一种突破(类访问限定符 封装)的方式,即在类外面也可以访问类里面的私有/保护成员。

友元的关键字:friend

友元的声明通常位于类的声明中,但其实现则位于类外部。

  • 友元分为2种:友元函数和友元类
    在这里插入图片描述

友元函数是一种特殊的函数,且它的声明是在类的内部,但它并不是类的成员函数

还有一个注意点是,只有类的静态成员或者静态成员函数才能直接用类名去访问。

在这里插入图片描述

class A
{
public:
	A(int a1)
		:_a1(3)
	{
	}
	int _a1=1;
};
int main()
{
    //这个是错误的
	std::cout << A::_a1 << std::endl;
	
   //这个是正确的
	A aa1(9);
	std::cout << aa1._a1 << std::endl;
}

在这里插入图片描述

class A
{
public:
	A(int a2)
	{
	}
	static int _a1;
	int _a2 = 9;
};

static int _a1 = 8;//static成员在全局初始化

int main()
{
	//静态成员函数可以用类名去访问
	std::cout << A::_a1 << std::endl;
}

‘全局函数’作友元

(某个全局函数) 想要访问 (类A里的私有成员),直接访问的话,编译器会报错。


办法:我们可以告诉编译器,这个全局函数是类A的好朋友,它是可以访问类A的私有成员的,可以放心,不会出事儿。


措施:在类的内部声明,全局函数是友元


//类A
class A
{
	friend void quanjv(A& a);

public:
	A(int a1, int a2)
		:_a1(a1)
		, _a2(a2)
	{
	}
private:
	int _a1;
	int _a2;
};
//全局函数
void quanjv(A& a)
{
	std::cout << a._a1 << std::endl;
}

int main()
{
	A a1(1, 2);
	quanjv(a1);
	return 0;
}

‘成员函数’作友元

(B的成员函数)想要访问(A的私有成员)


在A中声明友元函数,告诉编译器,B的某个成员函数是A的友元函数,可以访问A的私有成员。


class A
{
	friend void B::fang();
public:
	A(int a1)
		:_a1(3)
	{
	}
private:
	int _a1=1;
};
class B
{
public:
	B(int b1)
		:_b1(3)
	{
	}
	void fang()
	{
		A a1(9);
		std::cout << a1._a1 << std::endl;
	}

private:
	int _b1 = 1;
};

int main()
{
	B b1(8);
	b1.fang();
	return 0;
}

‘类‘作友元

在A类中声明友元函数,告诉编译器,B类是A类的好朋友,可以访问A类的私有成员

class A
{
	//告诉编译器,类B是类A的好朋友,B可以使用A的私有,保护成员
	friend class B;
public:
	A(int a1)
		:_a1(3)
	{
	}
private:
	int _a1 = 1;
};
class B
{
public:
	B(int b1)
		:_b1(3)
	{
	}
	void fang()
	{
		A a1(9);
		std::cout << a1._a1 << std::endl;
	}

private:
	int _b1 = 1;
};

int main()
{
	B b1(8);
	b1.fang();
	return 0;
}

二. 内部类

我们可以将其理解为嵌套,即:一个类里面,嵌套了另一个类。(在里面的那个类,叫做内部类。)

class A
{
 public:
     class B
     {}
}

那什么时候考虑使用内部类呢?

如果说,类B的出现就是为了供类A使用,那么可以将类B设置为A的内部类。如果将B放在private/protected位置,那么B类就是A类的专属内部类,其他地方都用不了。

内部类的特点:

  1. 内部类的本质是:封装。
  2. 内部类是外部类的友元。
  3. 当计算外部类的大小sizeof时,内部类不计算在其中。
  4. 内部类是一个独立的类,它并不是外部类的成员。跟定义在全局的类相比,唯一不同的就是:内部类受外部类的类域限制and访问限定符限制

在这里插入图片描述

由图片可知,在计算A的大小时,B并不计算在内,说明B并不是A的成员。它们是两个独立的类。

还有一个需要注意的点:静态成员可以直接用类域访问A::_k,普通成员必须是对象名.成员的形式访问a._h

三. 匿名对象

在之前,我们定义一个对象的办法是:类型 对象名(参数);

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
private:
	int _a;
};
int main()
{

	A a1(9);  //A   a1   (9);
	         //类型 对象名(参数)
	return 0;
}

现在有一种新的定义的方法:定义匿名对象 类型(参数); ,顾名思义即:匿名—>没有名字—>没有对象名

A(9);

匿名对象的特点:

  1. 生命周期短,仅存在于当行,到下一行就会调用它的析构函数。
  2. 调用一个类的成员函数时,会比较方便
class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	void fangwen(int q)
	{
		cout << q << endl;
	}
private:
	int _a;
};
int main()
{

	//之前调用成员函数的办法
	A a1(9);
	a1.fangwen(8);

	//采用匿名对象的方式
	A(9).fangwen(8);
	return 0;
}
  1. 匿名对象也可以被引用。(需要注意的是:匿名对象和临时对象一样,具有常性,引用的时候需要+const。匿名对象的生命周期会被延长)
	const A& a1 = A();
  1. 当函数的参数是自定义类型,需要给缺省参数时,可以采用匿名对象。(缺省值一般都是’常量’和’全局变量’)

在这里插入图片描述

注意点:匿名对象不传参时,也要有括号,和之前的定义方法不同(之前的方法,不传参时不能加括号)

int main()
{

	//之前调用成员函数的办法
	//有参数
	A a1(9);  //正确
	//不传实参
	A a1;     //正确
	A a1();   //错误,这样就分不清到底是‘函数声明’还是’定义对象‘

	//采用匿名对象的方式
	A(9);
	A();   //不传参时,必须有括号
	return 0;
}

四. 对象拷贝时的编译器优化

什么是编译器优化呢?

为了尽可能提高程序的效率,在不影响正确性的情况下会尽可能减少一些传参和传参过程中可以省略的拷贝

  1. 拷贝+构造拷贝----->拷贝A a1=1;

语法上是比较复杂的:
在这里插入图片描述

实际只调用了“构造函数”

在这里插入图片描述

  1. 隐式类型(函数中):构造+拷贝构造------->直接构造func(1);
    在这里插入图片描述

  2. 匿名对象

一个表达式中,连续构造+拷贝构造---->优化为一个构造
在这里插入图片描述

分析调用时的顺序

在这里插入图片描述


http://www.kler.cn/a/382337.html

相关文章:

  • 计算机基础复习12.23
  • 再服务器上建立新的编译环境
  • JavaScriptEs6 - String类和Array类扩展内容
  • 基于SpringBoot的山西文旅网系统
  • scala基础学习(数据类型)-字符串
  • 将HTML转换为PDF:使用Spire.Doc的详细指南(一) 试用版
  • 解释器模式:有效处理语言的设计模式
  • Redis 权限控制(ACL)|ACL 命令详解、ACL 持久化
  • 【题解】CF2033G
  • ThinkPHP腾讯云国际短信对接
  • W5100S-EVB-Pico2评估板介绍
  • 史上最全盘点:一文告诉你低代码(Low-Code)是什么?为什么要用?
  • 【青牛科技】GC8549替代LV8549/ONSEMI在摇头机、舞台灯、打印机和白色家电等产品上的应用分析
  • 100种算法【Python版】第48篇——计数排序
  • CNN在线识别手写中文
  • 小区搜索和SSB简介
  • Rust 异步编程实战
  • 总结:Vue2中双向绑定不生效的排查方法及原理
  • [云讷科技]DASA数字孪生机器人概念
  • 【5.8】指针算法-双指针验证回文串
  • 小语言模型介绍与LLM的比较
  • 【d63】【Java】【力扣】141.训练计划III
  • MFC,DLL界面库设计注意
  • 基于uniapp和java的电动车智能充电系统软件平台的设计
  • html checkbox和label 文字不对齐解决办法
  • 某华迪加现场大屏互动系统mobile.do.php任意文件上传