C++ Day04静态成员,友元,面向对象模型

&&静态成员
在类定义中,它的成员(包括成员变量和成员函数),这些成员可以用关键字static声明为静态的,称为静态成员。
不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。


1 静态成员变量
静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配空间。
*静态成员变量必须在类中声明,在类外定义。
静态数据成员不属于某个对象,在为对象分配空间中不包括静态成员所占空间。
静态数据成员可以通过类名或者对象名来引用。
2 静态成员函数
在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数使用方式和静态变量一样,同样在对象没有创建前,即可通过类名调用。静态成员函数主要为了访问静态变量,但是,不能访问普通成员变量。
静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员,完成对静态数据成员的封装。
静态成员函数只能访问静态变量,不能访问普通成员变量
静态成员函数的使用和静态成员变量一样
静态成员函数也有访问权限
普通成员函数可访问静态成员变量、也可以访问非经常成员变量
3 const静态成员属性

如果一个类的成员,既要实现共享,又要实现不可改变,那就用 static const 修饰。定义静态const数据成员时,最好在类内部初始化。(反过来写会报一大堆错误!)

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

class Person{
public:
	Person(){
		//sAge = 100; //不要在构造函数初始化
		flag = 0;
		count++;
	}

	static int sAge; //声明静态成员变量
	int flag;

	//1. 静态成员函数只能访问静态成员变量
	static void visitCount(){
		//flag++;
		count++;
	}
private:
	static int count;
};

//1. 静态成员变量必须在类内声明,类外初始化
int Person::sAge = 100; //类外初始化(类外定义)
int Person::count = 0;
void test(){

	cout << Person::sAge << endl;

	//1. 对象访问
	Person p;
	cout << p.sAge << endl;

	//2. 类名::
	cout << Person::sAge << endl;
}

//2. 静态成员变量是所有类共享
void test02(){
	
	Person p1;
	p1.flag = 100;
	p1.sAge = 100;
	Person p2;
	p2.flag = 200;
	p2.sAge = 200;

	cout << "p1:" <<  p1.flag << endl;
	cout << "p2:" <<  p2.flag << endl;
	//普通成员变量,p1有一份flag,p2也有自己的flag变量
	cout << "----------" << endl;
	cout << "p1:" << p1.sAge << endl;
	cout << "p2:" << p2.sAge << endl;

	//静态成员变量是所有对象共享的数据


	//静态成员变量也是有权限
	//Person::count = 100;
	//cout << Person::count << endl;

	Person::visitCount();

}

//1. 静态成员函数只能访问静态成员变量

int main(){

	//test();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

4 静态成员实现单例模式
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其默认构造函数和拷贝构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。

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

class Chairman{
private:
	//默认构造函数私有
	Chairman(){}
	Chairman(const Chairman&){} //拷贝构造函数私有
public:
	static Chairman* getInstance(){
		return sSingletong;
	}
private:
	static Chairman* sSingletong;
	//Chairman* sSingletong;//问题:能不能把sSingletong换成非静态?
};

//这个仍然是类外实现
Chairman* Chairman::sSingletong = new Chairman;


//1. 目标:不让用户能创建出来多个对象,只能创建一个

void test01(){

	Chairman* p1 = Chairman::getInstance();
	Chairman* p2 = Chairman::getInstance();

	if (p1 == p2){
		cout << "p1和p2是同一个对象!" << endl;
	}
	else{
		cout << "p1和p2不是同一个对象!" << endl;
	}

#if 0
	Chairman* p3 = new Chairman(*p1); //掉用默认拷贝构造函数

	if (p1 == p3){
		cout << "p1和p2是同一个对象!" << endl;
	}
	else{
		cout << "p1和p2不是同一个对象!" << endl;
	}
#endif

	//单例对象是不是全局都在使用,一个对象也占用不了多少内存
	//我们一般不考虑单例对象内存释放问题,程序结束之后由操作系统回收
}

int main(){

	test01();

	system("pause");
	return EXIT_SUCCESS;
}


单例模式打印机.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

class Printer{
private:
	Printer(){
		mCount = 0;
	}
	Printer(const Printer&){}
public:

	//打印函数
	void printText(string content){
		cout << "打印内容:" << content << endl;
		mCount++;
	}
	//获得打印已经打印的次数
	int getCount(){ return mCount; }

	//用于外界获得单例对象
	static Printer* getInstance(){
		return pPrinter;
	}
private:
	static Printer* pPrinter;
	int mCount;//统计打印打印次数
};

//类外初始化
Printer* Printer::pPrinter = new Printer;

void test(){

	//先拿到打印
	Printer* printer = Printer::getInstance();

	printer->printText("入职体检证明");
	printer->printText("学历复印件");
	printer->printText("社保文件");
	printer->printText("上家公司薪资流水");
	printer->printText("离职明证");

	cout << "打印使用次数:" << printer->getCount() << endl;
	
}

int main(){

	test();

	system("pause");
	return EXIT_SUCCESS;
}

&&C++面向对象模型初探

1 成员变量和函数的存储
“数据”和“处理数据的操作(函数)”是分开存储的。
c++中的非静态数据成员直接内含在类对象中,就像c struct一样。
成员函数(member function)虽然内含在class声明之内,却不出现在对象中。
每一个非内联成员函数(non-inline member function)只会诞生一份函数实例.

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

//为什么一个空类大小是1
//空数组大小为1是为了 数组[0] [1]...能够区分开来
class Person{
public:
	Person(){
		mA = 0;
	}
	int mA;
	static int mB; //1. 静态成员变量不占对象空间
	//2. 函数也不占对象空间,所有函数共享一个函数实例
	void func(){
		cout << "mA:" << this->mA << endl;
	} 

	//静态成员函数也不占对象空间
	static void sfunc(){
	} 
};

//结论:c++中对象函数和变量是分开存储的。并且对象的大小只包含普通成员变量


void test(){

	Person p1;
	Person p2;

	cout << sizeof(p1) << endl;

	p1.mA = 100;
	p2.mA = 200;

	//那个对象调用函数,this指针就指向谁
	p1.func();
	p2.func();

	
}

int main(){

	test();


	system("pause");
	return EXIT_SUCCESS;
}


通过上面的案例,我们可以的得出:C++类对象中的变量和函数是分开存储。


2 this指针
2.1 this指针工作原理
c++规定,this指针是隐含在对象成员函数内的一种指针。当一个对象被创建后,它的每一个成员函数都含有一个系统自动生成的隐含指针this,用以保存这个对象的地址,也就是说虽然我们没有写上this指针,编译器在编译的时候也是会加上的。因此this也称为“指向本对象的指针”,this指针并不是对象的一部分,不会影响sizeof(对象)的结果。
   this指针是C++实现封装的一种机制,它将对象和该对象调用的成员函数连接在一起,在外部看来,每一个对象都拥有自己的函数成员。
 this指针永远指向当前对象。


成员函数通过this指针即可知道操作的是那个对象的数据。This指针是一种隐含指针,它隐含于每个类的非静态成员函数中。This指针无需定义,直接使用即可。
注意:静态成员函数内部没有this指针,静态成员函数不能操作非静态成员变量。
2.2 this指针的使用
当形参和成员变量同名时,可用this指针来区分
在类的非静态成员函数中返回对象本身,可使用return *this

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

class Person{
public:
	Person(int age){
		this->age = age;
	}
	void ShowPerson(){
		cout << "Age:" << age << endl;
	}

	Person& PersonPlusPerson(Person& p){
		this->age += p.age;

		return *this;//=号赋值操作符,会使用返回*this
	}

	//成员变量
	bool PersonCompare(Person& p){
		if (this->age == p.age){
			return true;
		}
		return false;
	}
public:
	int age;
};

//全局比较两个person是否相等
bool PersonCompare(Person& p1, Person& p2){
	if (p1.age == p2.age){
		return true;
	}
	return false;
}

void test(){
	Person p1(10);
	Person p2(20);

	p1.PersonCompare(p2); // PersonCompare(&p1,p2);
	p1.PersonPlusPerson(p2).PersonPlusPerson(p2);

	cout << "p1.age:" << p1.age << endl;


	//p1.ShowPerson();
}

int main(){

	test();

	system("pause");
	return EXIT_SUCCESS;
}


2.3 const修饰成员函数
用const修饰的成员函数时,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量,
当成员变量类型符前用mutable修饰时例外。
2.4 const修饰对象(常对象)
常对象只能调用const的成员函数
常对象可访问 const 或非 const 数据成员,不能修改,除非成员用mutable修饰


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

class Person{
public:
	Person(){
		mA = 0;
		mB = 0;
	}

	//c++编译器偷偷给我们写的函数传入了一个指向当前对象的指针,指针叫做this指针
	void ShowPerson() const{
		//const Type* const pointer;
		//this = NULL; //不能修改指针的指向 Person* const this;
		//this->mA = 100; //但是this指针指向的对象的数据是可以修改的

		//函数后面加上const修饰谁?修饰的是this指针  const Person* const this;
		//const修饰函数之后,函数就不能通过内部的this指针修改对象数据了


		//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
		this->mB = 100;
	}

	void MyFunc() const{
		//mA = 10000;
	}

public:
	int mA;
	mutable int mB; //可修改 可变的
};


//const修饰对象  常量对象 常对象
void test02(){

	const Person person; //常量对象
	cout << person.mA << endl;
	//person.mA = 100; //常对象不能修改成员变量的值
	person.mB = 100; //但是常对象可以修改mutable修饰成员变量


	//常对象访问成员函数
	person.MyFunc(); //常对象只能调用const的函数



}
int main(){



	system("pause");
	return EXIT_SUCCESS;
}

&&友元
1 友元语法
friend关键字只出现在声明处
其他类、类成员函数、全局函数都可声明为友元
友元函数不是类的成员,不带this指针
友元函数可访问对象任意成员属性,包括私有属性
[友元类注意]
1.友元关系不能被继承。
2.友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。
3.友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。


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

//家
class Building{
	//声明goodGay 是我这个类的好基友,可以随意在我家玩耍
	//告诉编译器goodgay这个函数是当前类的朋友,可以肆无忌惮玩耍(访问任何变量和函数)
	friend void goodGay(Building& building); 
public:
	Building(){
		mSittingRoom = "客厅";
		mBedRoom = "卧室";
	}
public:
	string mSittingRoom; //客厅
private:
	string mBedRoom; //卧室
};

//好基友函数
void goodGay(Building& building){
	cout << "好基友在" << building.mSittingRoom << "玩耍!" << endl;
	cout << "好基友要去" << building.mBedRoom << "找男基友玩耍!" << endl;
}

void badGay(Building& building){
	cout << "坏基友在" << building.mSittingRoom << "玩耍!" << endl;
	//cout << "好基友要去" << building.mBedRoom << "找男基友玩耍!" << endl;
}


//goodGay是全局函数,没有this指针

int main(){

	//创建客厅
	Building building;
	goodGay(building);
	badGay(building);

	system("pause");
	return EXIT_SUCCESS;
}

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

class goodGay;

//房子
class Building{
	friend class goodGay;
public:
	Building();
public:
	string mSittingRoom; //客厅
private:
	string mBedRoom; //卧室
};


class goodGay{
public:
	goodGay();
	void visit();
	void visit2(Building* building);
private:
	Building* mBuilding; //building作为类的成员
};

goodGay::goodGay(){
	mBuilding = new Building;
}
void goodGay::visit(){
	cout << "访问" << mBuilding->mSittingRoom << endl;
	cout << "访问" << mBuilding->mBedRoom << endl;
}

void goodGay::visit2(Building* building){
	cout << "访问" << building->mSittingRoom << endl;
	cout << "访问" << building->mBedRoom << endl;
}


Building::Building(){
	mSittingRoom = "客厅";
	mBedRoom = "卧室";
}


int main(){


	Building building;
	goodGay gg;
	gg.visit();


	system("pause");
	return EXIT_SUCCESS;
}

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

class Building;

class goodGay{
public:
	goodGay();
	void visit();
	void visit2(Building* building);
private:
	Building* mBuilding; //building作为类的成员
};

//房子
class Building{
	friend void goodGay::visit2(Building* building);
public:
	Building();
public:
	string mSittingRoom; //客厅
private:
	string mBedRoom; //卧室
};

goodGay::goodGay(){
	mBuilding = new Building;
}
void goodGay::visit(){
	cout << "访问" << mBuilding->mSittingRoom << endl;
	//cout << "访问" << mBuilding->mBedRoom << endl;
}

void goodGay::visit2(Building* building){
	cout << "访问" << building->mSittingRoom << endl;
	cout << "访问" << building->mBedRoom << endl;
}


Building::Building(){
	mSittingRoom = "客厅";
	mBedRoom = "卧室";
}


int main(){



	system("pause");
	return EXIT_SUCCESS;
}



如果一个类被声明为friend,意味着它不是这个类的成员函数,却可以修改这个类的私有成员,而且必须列在类的定义中,因此他是一个特权函数。c++不是完全的面向对象语言,而只是一个混合产品。增加friend关键字只是用来解决一些实际问题,这也说明这种语言是不纯的。毕竟c++设计的目的是为了实用性,而不是追求理想的抽象。
                                                       --- Thinking in C++

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值