C++面向对象部分基础学习随笔


内存分区模型
c++程序在执行时,将内存大方向划分为4个区域
	·代码区:存放函数体和二进制代码,由操作系统进行管理
		程序运行前:
			存放CPU执行的机器指令
			代码区是共享的,共享的目的是对于频繁执行的程序,只需要在内中有一份代码即可。
			代码区是只读的,使其只读的原因是防止程序意外地修改它的指令。

	·全局区:存放全局变量和静态变量
		程序运行前:
			全局变量和静态变量存放在此
			全局区还包含了常量区:
				字符串常量和const修饰的全局常量
			该区域的数据在程序结束后由操作系统释放

	·栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
		注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器释放
			第一次可以打印正确数字,是因为编译器做了保留。第二次这个数据就不保留了

	·堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
		在C++中主要利用new在堆区开辟内存
			语法:new 数据类型
				int* p = new int(10);	//变量存放的值为10
				delete p;
			利用new创建的数据,会返回该数据对应的类型指针
				int* arr = new int[10];	//代表数组有十个元素
				delete[] arr;
		堆区开辟的数据,使用关键字delete释放内存
意义:
	不通区域存放的数据,赋予不通的生命周期,给我们更大的灵活编程。

全局变量
	在主函数外定义的变量
	int g_a =10;
静态变量
	static修饰的
	static int s_a = 10;
字符串常量
	(int)&"hello world";
const修饰的变量
	const修饰的全局变量
	const c_g_a = 10;
#####################################以上存放在全局区
	const修饰的局部变量
	const c_a = 10;
局部变量
	在函数中定义的变量
	int a = 10;

###########################################
引用:数据类型 &别名 = 原名;
		int &b = a;
	操作同一块内存
	·引用必须要初始化	int &b; x
	·引用一旦初始化后,就不可以更改了。
作用:函数传参时,可以利用引用技术让形参修饰实参
优点:可以简化指针修改实参
值传递
地址传递
引用传递:
	int a = 10;
	swap(a);
	swap(int &b){}		b引用a

引用做函数的返回值
	引用是可以作为函数的返回值存在的
	注意:不要返回局部变量引用
	用法:函数调用作为左值
引用的本质:
	引用的本质在c++内部实现是一个指针常量
	int a = 10;
	int &ref = a;  ------->>>>>>  int* const ref = &a;
	ref = 10 ;-------------->>>>> *ref = 10;

常量引用
使用场景:用来修饰形参,防止误操作
	const int &b = 10;		只读不可改
	void swap(const int &b){}
################################################
函数提高
在C++中,函数的形参列表是可以有默认值的
语法:返回值类型 函数名 (参数 = 默认值){}
注意事项;
	1、如果某个位置有了默认参数,那么从该位置往后,都必须有默认参数
	2、如果函数声明有默认参数,函数实现不能有默认参数
		声明和实现只能有一个有默认参数

占位参数
	voud func(int a, int)
		第二个int就是占位参数
	占位参数还可以有默认值
	void func(int a, int = 10)

函数重载:
作用:函数名可以相同,提高复用性
需满足的条件:
	·同一作用域下
	·函数名称相同
	·函数参数类型不同,或者个数不同,或者顺序不同
注意:
	函数的返回值不可以作为函数重载的条件 即(void int)类型不同,不可以

1、引用作为重载的条件
2、函数重载遇到默认参数
	函数重载的时候容易出现二义性,出现错误

*****************************************************
C++面向对象的三大特性:封装、继承、多态
封装:属性和行为
访问权限:
	public		公共权限	成员类内可以访问,类外也可以访问
	protected	保护权限	类内可以访问,类外不可以访问	子类可以访问
	private		私有权限	类内可以访问,类外不可以访问	子类不可以访问


structclass的区别
	struct	默认权限是public
	class	默认权限是private

成员属性设为私有
	优点:	·将所有成员属性设为私有,可以自己控制读写权限
			·对于写权限,我们可以检测数据的有效性

在类中可以使用另一个类作为成员

#pramga once	
类拆分
	.h		声明
		class cla{
		public:
			void func();
		}
	.cpp	实现
		void cla::func(){}
******************************************************
对象的初始化和清理
构造函数:
	主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
类名(){}
	1、构造函数,没有返回值也不用写void
	2、函数名称与类名相同
	3、构造函数可以有参数,因此可以发生重载
	4、程序在调用对象时,会自动调用构造,无须手动调用,而且只会调用一次

析构函数:
	主要作用在于对象销毁前系统自动调用,执行一些清理工作
~类名(){}
	1、析构函数,没有返回值也不用写void
	2、函数名称与类名相同,在名称前加上~
	3、析构函数不可以有参数,因此不可以发生重载
	4、程序在销毁对象前,会自动调用构造,无须手动调用,而且只会调用一次
		按任意键后才会调用

构造函数的分类:
	按照参数分为:	无参(默认构造)和有参构造
						Person(){}	Person(int a){}
	按照类型分为:	普通构造函数和拷贝构造函数
									Person(const Person &p)	//将传入的对象的所有属性,拷贝到该对象身上

调用:
	括号法
	Person p1;			//默认构造函数调用
	Person p2(10);		//有参构造函数
	Person p3(p2);		//拷贝构造函数
		注意事项:
			调用默认构造函数的时候,不要加()
			Person p1();	编译器会认为这是一个函数声明,不会认为在创建对象
	显示法
		Person p1;
		Person p2 = Person(10);		//有参构造
		Person p3 = Person(p2);		//拷贝构造
			等号右端如Person(10)---->>> 成为匿名对象,  特点:当前行执行结束后,系统会立即回收掉匿名对象(析构)
		注意事项:
			不要利用拷贝构造函数,初始化匿名对象,编译器会认为Person (p3) == Person p3;
	隐式转换法
		Person p4 = 10;		//有参构造法
		Person p5 = p4;		//拷贝构造法

拷贝构造函数调用时机
	·使用一个已经创建完毕的对象来初始化一个新对象
	·值传递的方式给函数参数传值
	·一值方式返回局部对象

构造函数的调用规则
默认情况下,C++编译器至少给一个类添加3个函数
	1、默认构造函数(无参,函数体为空)
	2、默认析构函数(无参,函数体为空)
	3、默认拷贝构造函数,对属性值进行值拷贝
构造函数调用规则如下:
	·如果用户定义有参构造函数,C++不在提供默认无参构造,但是会提供默认拷贝构造
	·如果用户定义拷贝构造函数,C++不会再提供其他构造函数
***************************************************************
在析构函数中,放置释放堆区的代码

深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝工作
深拷贝:在堆区重新申请空间,进行拷贝操作
如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

浅拷贝带来的问题是,堆区的内存重复释放。
	使用深拷贝解决该问题(即:在堆区再创建一块内存)

************************************************************
初始化列表哦
初始化列表来初始化类的属性

类对象作为类成员
	当其他类对象作为本类成员,构造的时候先构造类对象,再构造自身,析构的顺序与构造相反

静态成员
	静态成员就是在成员变量和成员函数前加上关键字static,成为静态成员
	·静态成员变量
		·所有对象共享同一份数据
		·在编译阶段分配内存
		·类内声明,类外初始化
	注意:static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。
		反过来说,没有在类外初始化的 static 成员变量不能使用。
		int Person::a = 10;
	·静态成员函数
		·所有对象共享同一个函数
		·静态成员函数只能访问静态成员变量
************************************************************
C++对象模型和this指针
在C++中,类内成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上

C++编译器会给每个空对象也分配一个字节的空间,是为了区分空对象占内存的位置
	********只有非静态成员变量,属于类的对象上
	静态变量,不属于类对象上
	非静态成员函数,不属于类对象上
	静态成员函数,不属于类对象上

this指针
	·解决名称冲突
	·返回对象本身用*this
this指针指向,被调用的成员函数,所属的对象 
this指向对象的指针

链式编程思想
	*this指向对象本体  *******无添加
	Person & ageAdd(Person & b){		//注意引用,,,,如果是Person ageAdd,则是d'f
		this->age += b.age;
		return *this;
	}
	Person p1(10);
	Person p2(10);
	p2.ageAdd(p1).ageAdd(p1).ageAdd(p1).ageAdd(p1).ageAdd(p1);

常函数
	void show() const
		{
			m_A = 100;		//错误
			m_B = 100//可以

		}	
		this指针的本质,是指针常量,指针的指向是不可以修改的
		在成员函数后面加const,修饰的是this指向,让指针指向的值也不可以修改
	mutable int m_B;	特殊变量,即使在常函数中,也可以修改这个值,加关键字mutable
		
常对象
	const Person p;		
	m_A		不可以修改
	m_B		可以修改
	常对象只可以调用常函数,不能调用普通成员函数
************************************************************
友元函数	可访问私有属性
	全局函数做友元
		在类中添加	friend 全局函数
	类做友元
		在类种添加	friend class 友元类名
	成员函数做友元
		在类种添加	friend	友元类名::func();

运算符重载:	成员函数的重载		全局函数的重载
概念:对已有的运算符进行重新定义,赋予其另一种功能,以适应不同的数据类型
	成员函数	classname operator+(classname &b){}
	全局函数	classname operator+(classname &a, classname &b){}

	运算符重载也就可以发生函数重载
左移运算符	<<
	用全局函数重载,不用成员函数
	classname operator+(cout , classname &p)
************************************************************
类需要初始化四个函数
仿函数
************************************************************
类的继承
	减少重复代码
语法: class 子类 :public 父类
继承方式:	公共继承
			保护继承
			私有继承

父类中所有非静态成员属性都会被子类继承下去
父类中私有成员属性是被编译器给隐藏了,因此访问不到,但是确实被继承下去了

如果通过子类访问父类中同名的成员。就加个作用域即可
子类会隐藏掉父类中的同名成员函数,加作用域可以访问到弗莱中的同名函数


//第一个::代表通过类名方式访问,第二个代表访问父类作用域下的成员
son::base::m_a;

利用虚继承 解决菱形继承问题
class son : virtual public base
************************************************************
多态
多态分为两类:
	静态多态:函数重载和运算符重载属于静态多态,复用函数名
	动态多态:派生类和虚函数实现运行时多态
静态与动态的区别;
	·静态多态的函数地址早绑定 - 编译阶段确定函数地址
	·动态多态的函数地址晚绑定 - 运行阶段确定函数地址

动态多态:
	有继承关系
	子类重写父类虚函数
多态的使用:
	·父类的指针或者引用 指向子类对象

当子类重写父函数
子类中的虚函数表 内部 会替换成 子类的虚函数地址

多态的优点:
	·代码结构清晰
	·可读性强
	·利于前期和后期的扩展以及维护

纯虚函数:
	virtual 返回值类型 函数名 (参数列表) = 0;
当类中有了纯虚函数,这个类也称为抽象类

抽象类的特点:
	·无法实例化对象
	·子类必须重写抽象类中的虚函数,否则也属于抽象类

利用虚析构可以解决 父类指针释放子类对象时不干净的问题
纯虚虚构,也需要具体实现

	·虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
	·如果子类中没有堆区函数,可以不写为虚构或纯虚析构
	·拥有纯虚析构函数的类也属于抽象类
************************************************************
文件操作
#include 
	文本文件
	二进制文件
ofstream	写
ifstream	读
fstream		读写
ofstream f;
f.open("文件路径“,打开方式);
f << "写入数据";
f.close();

文件打开方式:
		iso::in		为读文件二打开文件
		iso::out	为写文件而打开文件
		iso::ate	初始位置文件尾
		iso::app	追加方式写文件
		iso::trunc	如果文件存在先删除,再创建
		iso::binary	二进制方式
注意:文件打开方式可以配合使用,利用操作符 |
例如:用二进制方式写文件	iso::binary | iso::out
*/

你可能感兴趣的:(C语言+C++)