C++ 笔记 day29 静态成员 单例模式 this指针 常对象 友元

63 阅读4分钟

静态成员

image.png

静态成员变量

所有对象都共享同一份数据

编译阶段就分配内存

类内声明、类外初始化

访问方式有两种:通过对象访问、通过类名访问

静态成员变量也是有访问权限,私有权限类外访问不到

静态成员函数

所有对象都共享同一份函数

静态成员函数  只可以访问  静态成员变量,不可以访问非静态成员变量

静态成员函数  也是有访问权限的

静态成员函数 有两种访问方式:通过对象 、通过类名

image.png

示例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//1. 静态成员变量
class Person
{
public:
	//静态成员变量:编译阶段就分配了内存
	//类内声明、类外初始化
	//静态成员变量,所有对象都共享同一份数据
	static int m_A;
	int m_C;
	//2. 静态成员函数
	//所有对象都共享同一个func函数
	static void func() 
	{
		m_A = 100; //静态成员函数只能修改静态成员变量
		// m_C = 100; 报错,非静态成员变量不可以访问,因为无法区分到底要修改哪个对象
		cout << "func的调用" << endl;
	}
private:
	static int m_B; //私有的静态成员变量,有访问权限,私有权限类外访问不到
	static void func2();
};

int Person::m_A = 0; //要写作用域

void test01() 
{
	//1. 通过对象进行访问
	Person p1;
	cout << p1.m_A << endl;

	Person p2;
	p2.m_A = 100;
	cout << p1.m_A << endl;
	//2. 通过类名进行访问
	cout << Person::m_A << endl;

	//静态成员变量也是有访问权限的,私有权限类外访问不到
	//cout <<Person :: m_B << endl; 访问不到,因为是私有权限
}

//静态成员函数两种调用方式
void test02() 
{
	//通过对象
	Person p1;
	p1.func();
	//通过类名
	Person::func();

	//Person::func2(); 无法调用,也是访问权限的
}

int main()
{
	test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

单例模式

单例模式 – 主席类案例

通过一个类 只能实例化唯一的一个对象

image.png

  1. 私有化

    默认构造

    拷贝构造

  2. 唯一实例指针

  3. 对外提供 getInstance 接口,将指针返回

示例:主席类

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//主席类
class ChairMan 
{
public:
	static ChairMan* getInstance() 
	{
		return singleMan;
	}
private:
	//将构造函数私有化,不可以创建多个对象
	ChairMan() 
	{
	
	};
	ChairMan(const ChairMan&) //解决可以通过拷贝建立新的对象的过程
	{
	}
//public:
private:
	//将主席指针私有化,对外提供只读接口
	static ChairMan* singleMan;//类内声明,类外初始化

};

ChairMan* ChairMan::singleMan = new ChairMan;

void test01() 
{
	//ChairMan* c1 = ChairMan::singleMan;
	//ChairMan* c2 = ChairMan::singleMan;
	ChairMan* c1 = ChairMan::getInstance();
	ChairMan* c2 = ChairMan::getInstance();

	//ChairMan* c3 = new ChairMan(*c1); 

	
	if (c1 == c2) 
	{
		cout << "c1=c2" << endl;
	}
	else 
	{
		cout << "c1 != c2" << endl;
	}

	if (c1 == c3)
	{
		cout << "c1=c3" << endl;
	}
	else
	{
		cout << "c1 != c3" << endl;
	}
}

int main()
{

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

单例模式 – 打印机案例

和主席类案例一样设计单例模式

提供打印功能并且统计打印次数

示例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

class Printer 
{
public:
	static Printer* getInstance() 
	{
		return printer;
	}
	void printText(string text) 
	{
		m_Count++;
		cout << text << endl;
	}
	int m_Count;
private:
	//编译阶段就分配内存,可以通过这种方法在main函数调用之前打印
	Printer() 
	{
		m_Count = 0;
		cout << "打印机的构造调用" << endl;
	}
	Printer(const Printer& p) 
	{
	
	}

	static Printer* printer;
};

Printer* Printer::printer = new Printer;

void test01() 
{
	Printer* p1 = Printer::getInstance();
	p1->printText("入职证明");
	p1->printText("离职证明");
	p1->printText("加薪申请");
	p1->printText("旅行申请");

	cout << "打印机使用次数" << p1->m_Count << endl;
	Printer* p2 = Printer::getInstance();
	p2->printText("调休申请");
	cout << "打印机使用次数" << p2->m_Count << endl;
}

int main()
{
	cout << "main函数调用" << endl;
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

C++对象模型初探

类中的成员变量 和 成员函数  是分开存储的

只有非静态成员变量  属于类对象上

空类的sizeof结果  1

示例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;


class Person 
{
public:
	int m_A; //只有非静态成员变量 属于类对象上

	void func() //成员函数  并不属于类对象上
	{
	
	}

	static int m_B;//静态成员变量 不属于类对象上

	static void func2() //静态成员函数  不属于类对象上 
	{
	
	}

	double m_C; //以8位模数对齐

};

int Person::m_B = 0;

void test01() 
{
	//空类的sizeof结果是1,原因 每个对象都应该在内存上有独一无二的地址,因此给空对象分配1个字节空间
	Person p1;

	cout << "sizeof = " << sizeof(p1) << endl;
}

int main()
{

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

this指针

this指针 指向 被调用的成员函数 所属的对象

  1. this指针可以解决名称冲突

  2. this指针 隐式加在每个成员函数中

  3. *this 就是本体

      p1.personAddPerson(p2).personAddPerson(p2).personAddPerson(p2); //链式编程
    

示例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person 
{
public:
	Person(int age) 
	{
		// 用途1 解决名称冲突
		this->age = age;
	}
	//this 指针 隐式加在每个成员函数中
	bool cmpareAge(Person & p) 
	{
		if (this->age == p.age) 
		{
			return true;
		}
		return false;
	}

	Person& persnAddPerson(Person& p) 
	{
		this->age += p.age;
		return *this;//用引用的方式返回本身,可以多次复用链式编程
	}
	int age;
};

void test01() 
{
	//this 指针 指向被调用的成员函数所属的对象
	Person p1(18);
	cout << "p1 age " << p1.age << endl;

	Person p2(18);
	bool ret = p1.cmpareAge(p2);
	if (ret) 
	{
		cout << "p1 == p2" << endl;
	}
	//上面的函数如果不是返回引用改为返回值,则只有第一次调用是p1,后面调用的是拷贝构造函数生成的p1拷贝,不是p1本身
	p1.persnAddPerson(p2).persnAddPerson(p2).persnAddPerson(p2); //链式编程
	cout << "age of p1:" << p1.age << endl;
}

int main()
{

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

空指针访问成员函数

  1. 如果成员函数中没有用到this指针,可以用空指针调用成员函数

  2. 如果成员函数中用到了this,那么这个this需要加判断,防止代码down掉

示例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person
{
public:
	void showClass()
	{
		cout << "class Name is Person" << endl;
	}
	void showAge() 
	{
		if (this == NULL) //防止别人用空指针调用成员函数代码崩掉
		{
			return;
		}
		m_Age = 0;
		cout << "age = " << this->m_Age << endl;
	}
	int m_Age;
};

void test01() 
{
	Person* p = NULL;

	p->showClass();
	p->showAge();
}

int main()
{
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

常对象和常函数

常函数

成员函数 声明后面加const

void showPerson() const

const目的是为了修饰成员函数中的this指针,让指针指向的值不可以修改

有些属性比较特殊,依然在常函数或者常对象中可以修改,需要加入关键字 mutable

常对象

const Person p

常对象也不许修改成员属性

常对象只能调用常函数

对于成员函数 ,不可以 用static 和 const同时修饰

友元

程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。

全局函数作为友元函数

利用friend关键字让全局函数 goodGay作为本类好朋友,可以访问私有成员

friend  void goodGay(Building * buliding);

示例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>

class Building 
{
	//利用friend关键字让全局函数 goodGay作为本类友元 可以访问私有属性
	friend void goodGay(Building* building);
public:
	Building() 
	{
		this->m_SittingRoom = "客厅";
		this->m_BedRoom = "卧室";
	}

public:
	string m_SittingRoom; //客厅
private:
	string m_BedRoom;//卧室

};
//好基友 全局函数 可以访问  Building的私有属性
void goodGay(Building* building) 
{
	cout << "好基友正在访问" << building->m_SittingRoom << endl;
	cout << "好基友正在访问" << building->m_BedRoom << endl;
}

void test01() 
{
	Building building;
	goodGay(&building);
}

int main()
{

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

类作为友元类

让goodGay类作为 Building的好朋友,可以访问私有成员

friend class GoodGay;

示例:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
class Building;

class goodGay 
{
public:
	goodGay();

	void visit();

	Building* m_building;
};

class Building 
{
	//让goodGay类作为Building的好朋友可以访问私有成员
	friend class goodGay;
public:

	Building();

	string m_SittingRoom;
private:
	string m_BedRoom;
};
//Building构造函数的类外实现
Building::Building() 
{
	this->m_SittingRoom = "客厅";
	this->m_BedRoom = "卧室";
}
goodGay::goodGay() 
{
	this->m_building = new Building;
}
void goodGay::visit() 
{
	cout << "好基友正在访问:" << this->m_building->m_SittingRoom << endl;
	cout << "好基友正在访问:" << this->m_building->m_BedRoom << endl;
}

void test01() 
{
	goodGay gg;
	gg.visit();
}

int main()
{
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

类中的成员函数作为友元函数

让GoodGay类中的 visit成员函数作为友元

friend void GoodGay::visit();

示例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
class Building;

class goodGay
{
public:
	goodGay();

	void visit(); //可以访问Building的私有

	void visit2(); //不可以访问Building的私有

	Building* m_building;
};

class Building
{
	//让goodGay中的visit成员函数作为友元
	friend void goodGay::visit();
public:

	Building();

	string m_SittingRoom;
private:
	string m_BedRoom;
};
//Building构造函数的类外实现
Building::Building()
{
	this->m_SittingRoom = "客厅";
	this->m_BedRoom = "卧室";
}
goodGay::goodGay()
{
	this->m_building = new Building;
}
void goodGay::visit()
{
	cout << "好基友正在访问:" << this->m_building->m_SittingRoom << endl;
	cout << "好基友正在访问:" << this->m_building->m_BedRoom << endl;
}
void goodGay::visit2()
{
	cout << "好基友正在访问:" << this->m_building->m_SittingRoom << endl;
	cout << "好基友正在访问:" << this->m_building->m_BedRoom << endl; //报错
}

void test01() 
{
	goodGay gg;
	gg.visit2();
}
int main()
{
	test01();


	system("pause");
	return EXIT_SUCCESS;
}