C++进阶之路《四》

一.友元

友元的特点

1.友元没有自反性:A是B的友元,B不是A的友元
2.友元不具有传递性:A和B是友元,B和C是友元,A和C不是友元
3.友元无继承性
4.友元无访问权限

友元的实现方案

1.外部函数友元
在这里插入图片描述
2.成员函数友元
在这里插入图片描述
3.类友元
想让Object中的所有成员函数均能访问Base这个类型所产生对象的公有,私有和保护属性。直接将Object类注册成Base类的友元
在这里插入图片描述

二.静态成员

静态成员初始化

在这里插入图片描述

C语言:

1).static修饰局部变量:

  1. 变量可见性不变;
  2. 生存区变到.data区,生存期变长,可以拿引用返回该局部变量
  3. 只对其初始化一次
    在这里插入图片描述

2).static修饰全局变量

  1. 生存区不变,依旧在.data区
  2. 可见性降低。只在定义该变量的文件中可见,对于同一个工程的其他文件不可见

3).static修饰函数

  1. 生存区不变,依旧在代码区(.text区)
  2. 可见性降低。只在定义该变量的文件中可见,对于同一个工程的其他文件不可见

C++

静态数据成员:
1.静态成员只能在类外进行初始化
2.不能在构造函数或拷贝构造函数中对静态成员进行构建
3.类里面声明的静态成员是所有对象所共享的
4.静态函数没有this指针,所以静态函数内部不能访问对象的普通成员,只能访问静态成员
5.静态函数内部访问对象的普通成员,必须把对象作为参数传递给函数在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

单例模式

只能创建一个对象
Windows上的回收站就是一个单例模式,每一次运行打开只能产生一个界面

饿汉模式:

程序运行的过程中一旦调用其构造函数就直接给予构建

线程安全

无论如何只能得到同一个对象。构建的单例对象是线程安全的

class Object
{
private:
	int value;
	static Object instance;
	//static int num;
private:
	Object(int x = 0) :value(x) {}
	Object(const Object& obj) = delete;
	Object& operator=(const Object& ob) = delete;
public:
	static Object& GetInstance()
	{
		return instance;
		//只能使用引用或指针返回。若以值的形式返回必定调用拷贝构造函数生成临时对象进行过渡,但是拷贝构造函数已经删除了
	}
};

//int Object::num = 10;
Object Object::instance(10);//静态成员的初始化,由于不是一个语句,编译时就需要对其进行实例化,即进入主函数之前就需要把实体构建出来
//类型  作用域
//语句:函数内部的一条条代码称为语句
//int main()
//{
//	Object& obja = Object::GetInstance();
//	Object& objb = obja.GetInstance();
//
//	cout << &obja << endl;
//	cout << &objb << endl;
//	return 0;
//}

void funa()
{
	Object& obja = Object::GetInstance();
	cout << &obja << endl;
}

void funb()
{
	Object& objb = Object::GetInstance();
	cout << &objb << endl;
}

int main()
{
	thread tha(funa);
	thread thb(funb);

	tha.join();
	thb.join();

	return 0;
}
线程不安全
class Object
{
private:
	int value;
private:
	Object(int x = 0) :value(x) {}
	Object(const Object& obj) = delete;
	Object& operator=(const Object& ob) = delete;
public:
	static Object& GetInstance()
	{
		static Object instance(10);
		return instance;
	}

};

改进:

class Object
{
private:
	int value;
private:
	Object(int x = 0) :value(x) {}
	Object(const Object& obj) = delete;
	Object& operator=(const Object& ob) = delete;
public:
	static Object& GetInstance(int x)
	{
		static Object instance(x);
		return instance;
	}

};

懒汉模式

需要的时候再进行构建对象。由于对象是new出来的存在于.heap区,所以对于多线程来说可能创建多个对象,故该方法线程完全不安全,因此需要加锁

std::mutex mtx;

class Object
{
private:
	int value;
	static Object* pobj;
private:
	Object(int x = 0) :value(x) {}
	Object(const Object& obj) = delete;
	Object& operator=(const Object& ob) = delete;
public:
	static Object* GetInstance()
	{
		std::lock_guard<std::mutex>lock(mtx);
		if (pobj == NULL)
		{
			std::this_thread::sleep_for(std::chrono::milliseconds(10));
			pobj = new Object(10);
		}
		return pobj;
	}
};
Object* Object::pobj = NULL;

void funa()
{
	Object* obja = Object::GetInstance();
	cout << obja << endl;
}

void funb()
{
	Object* objb = Object::GetInstance();
	cout << objb << endl;
}

int main()
{
	thread tha(funa);
	thread thb(funb);

	tha.join();
	thb.join();

	return 0;
}

三.模板

类模板要比函数模板简单。主要是因为函数模板在编译的过程中有一个实参到形参的推演过程;而类模板可以直接给出类型
指针和引用都是和变量名结合

在这里插入图片描述在这里插入图片描述

函数模板

函数模板形参推演

在这里插入图片描述

template<class T>
void fun(T a)
{
	T x, y;
	cout << " T type: " << typeid(T).name() << endl;
	cout << " a type: " << typeid(a).name() << endl;
}
int main()
{
	int x = 10;
	const int y = 10;
	int* xp = &x;
	const int* yp = &y;
	fun(xp);
	fun(yp);
	return 0;
}

在这里插入图片描述

template<class T>
void fun(T* a)
{
	T x, y;
	cout << " T type: " << typeid(T).name() << endl;
	cout << " a type: " << typeid(a).name() << endl;
}
int main()
{
	const int y = 10;
	fun(&y);
	return 0;
}

由于y是常量,所以模板推演时T为const int类型,故函数模板体的x与y必须进行初始化,否则无法编译通过

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

函数模板可以进行特化

在这里插入图片描述

函数模板可以进行重载

在这里插入图片描述

类模板

类模板不存在推演过程。模板类是编译时完成代码的生成
类模板中定义的函数都是模板函数
若没有调用该函数,编译器不会对此函数进行实例化

模板类型

在这里插入图片描述

非模板类型

代表一种常量,进行替换规则

在这里插入图片描述

缺省的模板类型

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值