C++语言学习笔记4

五大对象的生命周期

#include <iostream>
using namespace std;


class CTest
{
public:
	CTest() {
		cout << "CTest()" << endl;
	}
	~CTest() {
		cout << "~CTest()" << endl;
	}
protected:
private:
};

CTest tst2;	//3. 全局对象 程序启动自动为对象分配空间,直到程序结束生命周期结束(看什么时候调用析构函数)

static CTest tst3;	//4. 静态全局对象 程序启动自动为对象分配空间,直到程序结束生命周期结束(看什么时候调用析构函数)

//全局对象和静态全局对象的区别:作用范围不同,静态全局对象为文件作用域,全局对象为整个项目工程。也就是说在两个源文件中,不可以重复定义两个名字类型一样的全局对象,但可以重复定义两个名字类型一样的静态全局对象

CTest* ptst = NULL;
void show() {
	static CTest tst;//生命周期 无论调用几次该函数,其都在第一次调用该函数的时候创建对象,直到程序结束,在内存中只有一份
	ptst = &tst;//取出tst的地址放在ptst这个指针里
}//无论运行多少遍这个函数,tst对象的地址都不会变

//5. 临时对象
CTest GetTest() {
	CTest tst;
	return tst;
}

int main() {

	//cout << "-------------------" << endl;
	//CTest tst;	//1. 局部对象(栈区),只在当前函数内生效,生命周期在函数结束时结束
	//
	//CTest* pTst = new CTest;	//2. new对象,生命周期需要delete才会结束

	show();

	CTest tst();
	调用无参构造时不要这样写,有时候编译器会误认为这是函数说明,应写:Ctest tst;
	//
	//cout << "-------------------" << endl;
	//CTest(2);//临时对象(匿名对象) 其生命周期只有当前这一行,遇到这一行的;以后就会被回收
	//cout << "-------------------" << endl;

	cout << "-------------------" << endl;
	GetTest();
	cout << "-------------------" << endl;

	system("pause");
	return 0;
}

类的初步认识

#include <iostream>
using namespace std;


class Ctest {
public:
	int m_a;
public:
	Ctest(int a) {
		m_a = a;
	}
	~Ctest() {
	
	}
	void show() {
	
	}
	void play() {
	
	}
};

int main() {

	//Ctest tst;
	//cout << sizeof(tst) << endl;
	//cout << sizeof(Ctest) << endl;	
	空类定义的对象的大小输出1  起到占位的作用,标识该对象在内存空间是真实存在的

	//Ctest tst;
	//cout << sizeof(tst) << endl;
	//cout << sizeof(Ctest) << endl;
	类中有int后,不再需要占位了,因为int的4个字节本身已经存在了,所以该大小输出为4而非5,不再需要加上占位的1
	类中写了两个空函数后依然输出4,能说明类成员属性占用对象的内存空间,定义对象时存在;类成员函数不占用对象的内存空间,其占用的是应用程序的内存空间,在编译期就存在(程序启用之前,嵌入在exe程序文件内)

	Ctest tst1(1);
	Ctest tst2(2);
	//断点调试中局部变量表中可以看到tst1中m_a是1,tst2中m_a是2,说明类成员属性中,两个对象在两个不同的内存空间中存在两份,也就是说多个对象存在多份,几个对象存在几份,但类成员函数并非如此,其属于类,不属于对象,因此只有一份

	system("pause");
	return 0;
}

this 指针

#include <iostream>
using namespace std;


class Ctest {
public:
	int m_a;
public:
	Ctest(int a) {
		m_a = a;
	}

	//this 指针 : CTest* const this;
	//类中非静态成员函数中有一个默认的隐含的参,this指针
	//this 指针:用于连接成员属性和成员方法的桥梁,哪个对象调用了函数this指针就指向哪个对象
	void show(/* CTest* const this */) {
		cout << m_a << endl;
		//cout << this->m_a << endl;
	}

	void play(/* CTest* const this */) {
		cout << "play()" << endl;
		//cout << m_a << endl;
	}

};

int main() {

	//Ctest tst1(1);
	//tst1.show();//将tst1这一对象的地址给this,然后对应输出this的m_a也就是tst1这一对象内定义的m_a的值为1
	//Ctest tst2(2);
	//tst2.show();//将tst2这一对象的地址给this,然后对应输出this的m_a也就是tst2这一对象内定义的m_a的值为2

	Ctest* p = NULL;
	//p->m_a = 10;	//程序崩溃
	p->play();	//没有对象,此时this指针为NULL,调用play这一函数时如果没有使用到成员变量m_a则可正常运行,但如果使用到m_a则程序崩溃,说明this这一指针确实链接了对象(成员变量)和该函数(成员方法)


	system("pause");
	return 0;
}

静态成员属性

#include <iostream>
using namespace std;

class CTest {
public:
	static int m_a;
	CTest() {
		cout << m_a << endl;
		m_a = 20;	//赋值
	}//	构造函数在创建对象的时候去执行,因此m_a = 10的初始化要等定义了对象再去初始化,但这与“静态成员属性不属于对象,属于类”相违背。而实际上此处并非初始化,而是初始化之后的一个赋值。
    
    //变量初始化指的是变量在定义的时候的赋值,而m_a这个变量作为staitc的静态成员属性,静态成员属性编译器就存在了,同时需要在类外进行初始化,因此等代码跑到m_a = 20这一行时,由于m_a已经定义初始化为20了,所以这一行只能是修改m_a的赋值
    
};

//类型 类名即作用域::变量名 = 初始化值
int CTest::m_a = 10;	//类外初始化,如果有多个类中都有m_a需要定义,那么需要作用域来区分,所以定义的时候需要有类名~

int main() {

	CTest tst;//定义对象时触发了构造函数,此时报错:无法解析外部符号m_a,也就是说m_a声明了但没有定义。而其不属于对象,所以应该在类外进行定义。(int CTest::m_a = 10;)

	cout << sizeof(CTest) << endl;	//输出1:说明依然占位,则静态成员属性不属于对象,属于类
	cout << CTest::m_a << endl;	//由于静态成员属性不属于对象,属于类,因此可以直接通过类名作用域来使用这一成员,比如CTest::m_a,当然以对象使用也可以,如下:cout<<tst.m_a<<endl;
	system("pause");
	return 0;
}

	//输出结果: 10 1 20(先类外初始化,然后进构造函数进行赋值)

静态成员变量

#include <iostream>
using namespace std;

class CTest {
public:
	static int m_a;
	CTest() {
		cout << m_a << endl;
	}
    
	void Show() {
		cout << m_a << endl;	//this->m_a
	}
};

int CTest::m_a = 10;

int main() {

	CTest tst1;
	cout << tst1.m_a << endl;
	tst1.m_a = 12;
	CTest tst2;
	cout << tst2.m_a << endl;
	//所有对象共享该静态成员变量,也就是说,其中一个对象改了后,其他的也会改

	system("pause");
	return 0;
}

	//输出结果: 10 10 12 12(输出顺序为tst1构造函数 tst1.m_a tst2构造函数 tst2.m_a)

静态成员函数

#include <iostream>
using namespace std;

class CTest {
public:
	static int m_a;
	int m_b;

	void Show() {
		cout << m_a << endl;	//this->m_a
		cout << m_b << endl;	//this->m_b
		this;
        CTest::play();
	}

	//静态成员函数
	//和普通函数一样,编译期就存在,属于类并只有一份,但两者最大的区别在于this指针
	//和静态成员变量一样,可以用对象去使用,也可通过类名作用域去使用
	static void play() {
		cout << "void play()" << endl;
		cout << m_a << endl;
		//cout << m_b << endl;//报错:对非静态成员CTest::m_b的非法引用
		//原因:静态成员函数在编译期就存在,不需要通过对象,但m_b此时根本不存在
		//this;//报错:this只能用于非静态成员函数的内部,也就是说,静态成员函数没有隐藏的this指针
		
	}
};

int CTest::m_a = 10;

int main() {

	CTest tst;
	tst.play();
	CTest::play();

	system("pause");
	return 0;
}

初始化参数列表

#include <iostream>
using namespace std;


class CTest {
public:
	const int m_a;
	int m_b;
	//初始化参数列表:真正的初始化
	CTest() :m_a(10), m_b(30) {//无参的初始化参数列表
		//m_a = 10;	
		//报错 此处为赋值 不是初始化 而const定义的是常量 所以不是可以修改的左值
		//m_b = 20;//普通变量可以这样初始化,也可以通过初始化参数列表进行真正的初始化,那么此处也可以等于是赋值
	}
};

int main() {

	CTest tst;
	cout << tst.m_a << endl;
	cout << tst.m_b << endl;

	system("pause");
	return 0;
}

初始化参数列表的初始化顺序

class CTest {
public:
	const int m_a;
	int m_b;

	//有参的初始化参数列表
	//初始化参数列表的初始化顺序:并不是写在参数列表中的顺序,而是变量在类中定义的顺序,也就是m_a,m_b
	//

	//CTest(int a) :m_a(m_b), m_b(a) {	//m_a没有初始化
	//	//用m_b去初始化m_a,但m_b的定义在m_a后,因此无法完成该初始化
	//}

	CTest(int a) :m_a(a), m_b(m_a) {

	}
};

const成员函数/常函数

#include <iostream>
using namespace std;


class CTest {
public:
	const int m_a;
	int m_b;
	CTest() :m_a(10), m_b(30) {
		
	}

	//const int show() {//返回值为常量(const int)
	//	
	//}


	void play(/*CTest* const this*/) {
	
	}

	//const成员函数(常成员函数):注意const要加在参数列表后面
	//常函数中可以使用 但不能修改
	int show (/* const CTest* const this */)const {
		//const修饰的是this指针,普通函数的this指针为CTest* const this,而常函数的为const CTest* const this
		cout << m_a << endl;
		cout << m_b << endl;

		//m_a = 20;
		//m_b = 20;
		//通过常量对象进行访问,因此无法修改

		return 0;
	}
};

int main() {

	CTest tst;
	tst.show();//普通对象可以调用普通函数和常函数

	//const CTest* const pp = &tst;	//指针的安全级别升级操作,是允许的
	//pp->m_a = 10;	//m_a无法修改,因为pp指针被const修饰了,也就是常函数隐含的const CTest* const this

	const CTest tst1;//常量对象:只能调用常函数,不可以调用普通函数
	tst1.show();

	//tst1.play();		//报错,无法调用
	//CTest* const p2 = &tst1;		//报错,为指针的安全级别降级操作,这是不被允许的

	system("pause");
	return 0;
}

类之间的横向关系

#include <iostream>
using namespace std;

//类之间的横向关系

class CFriend {
public:
	void play() {
		cout << "上号,开黑啦!" << endl;
	}

};

class CComputer {
public:
	void Complie() {
		cout << "正在编译代码呀~" << endl;
	}

};

class CHand {
public:
	void Move() {
		cout << "手 移动啦" << endl;
	}

};

class CPeople {
public:
	CHand m_hand;
	CFriend* m_pFriend;

	CPeople() {
		m_pFriend = NULL;
	}
	~CPeople() {
		
	}

	void Clap() {
		m_hand.Move();
		cout << "鼓掌拉 123 123 12333333" << endl;
	}
	void Code(CComputer* computer) {
		if (computer)
		{
			m_hand.Move();
			cout << "写代码啦 劈里啪啦" << endl;
			computer->Complie();
			cout << "生成可执行程序" << endl;
		}
	}

	void SetFriend(CFriend *pFriend) {
		m_pFriend = pFriend;
	
	}

	void PlayGame() {
		if (m_pFriend)
		{
			m_pFriend->play();
			cout << "五杀!" << endl;
		}
		else {
			cout << "朋友不理我了,孤儿自己开黑" << endl;
		}
	}

};

class CFamily {
public:
	CPeople* m_pPeople[10];
	CFamily() {
		for (int i = 0; i < 10; i++) 
		{
			m_pPeople[i] = NULL;
		}
	}
	~CFamily() {
		for (int i = 0; i < 10; i++)
		{
			if (m_pPeople[i])
			{
				delete m_pPeople[i];
				m_pPeople[i] = NULL;
			}
		}
	}

	void PushPeople(CPeople* pPeople) {
		for (int i = 0; i < 10; i++)
		{
			if (m_pPeople[i] == NULL) 
			{
				m_pPeople[i] = pPeople;
				return;	//	不写return的话会一直添加到第十个位置为止
			}
		}
	}

	void AllPeopleCode(CComputer* computer) {
		for (int i = 0; i < 10; i++) {
			if (m_pPeople[i])
			{
				m_pPeople[i]->Code(computer);
			}
		}
	
	}
};


int main() {
	
	//复合—————————————————————————————————————————————
	CPeople people1;
	people1.Clap();
	//————————————————————————————————————————————————


	//依赖—————————————————————————————————————————————
	CComputer* pComp = new CComputer;
	people1.Code(pComp);
	delete pComp;
	pComp = NULL;
	people1.Code(pComp);
	//————————————————————————————————————————————————
	

	//关联—————————————————————————————————————————————
	CFriend* pFriend = new CFriend;
	people1.SetFriend(pFriend);
	//people1.m_pFriend = pFriend;
	//不通过函数交朋友,直接通过成员变量赋值交朋友也是可行的
	people1.PlayGame();
	
	delete pFriend;
	pFriend = NULL;
	people1.m_pFriend = NULL;//朋友没了

	people1.PlayGame();
	//————————————————————————————————————————————————


	//聚合—————————————————————————————————————————————
	CFamily Workfamily;
	CPeople* pPeople1 = new CPeople;
	CPeople* pPeople2 = new CPeople;

	Workfamily.PushPeople(pPeople1);
	Workfamily.PushPeople(pPeople2);
	
	CComputer* pComp1 = new CComputer;
	Workfamily.AllPeopleCode(pComp1);

	//————————————————————————————————————————————————


	system("pause");
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

97Marcus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值