C++面向对象学习(1)--- 封装

在这里插入图片描述



权限相关

|| 三种权限

在C++中 struct和class唯一的区别就在于 默认的访问权限不同
		class默认是私有权限, struct默认是公共权限
		三种权限
		公共权限  public     类内可以访问  类外可以访问
		私有权限  private    类内可以访问  类外不可以访问 (同时不可继承)
		保护权限  protected  类内可以访问  类外不可以访问 (但可以被继承)
		
class Person {
	int m_age = 1;   		  等同于:// private:
 	 								  // int int m_age = 1;   
 };

构造函数与析构函数

|| 一个类中默认封装的函数:

1,无参构造函数
2,拷贝构造函数(浅拷贝)
3,析构函数

|| 深究构造函数:

	构造函数的格式 : 1,无返回类型 2,函数名必须为类名
	构造函数的分类: 1,有无参构造函数   2,拷贝构造函数
	构造函数的调用方式 1,括号法   2,隐式法  3,显示法

|| 拷贝构造函数的使用情景:

	1,复制一个相同对象时
	Person p1(p2);
	2,(值传递)以对象作为函数参数时
	void doWork(Person p1)  == void doWork (Person p1 = p)   // p1是p的副本
	
	3, 接收一个函数的返回对象时     
	Person p2 = doWork();
	Person  doWork()
	{
		Person p1;
		return p1;	
	}

|| 拷贝构造函数的浅拷贝与深拷贝:

	在涉及内存释放的问题时,浅拷贝带来的重复释放堆区问题
	浅拷贝:简单的赋值拷贝操作
	深拷贝:在堆区重新申请空间,进行拷贝操作
	
	总结一下就是:使用new创建变量的 拷贝构造函数 是 深拷贝构造函数,非则否
	根本区别在于数据存放在堆区还是栈区(是不是new出来的)浅拷贝共用一段内存中的
	数据,深拷贝使用另外一段内存中的数据(程序员使用new开辟的)。
	
	
	
	Person(const Person& p) {
		cout << "拷贝构造函数!" << endl;
		m_age = p.m_age;
		//m_height = p,height;    --- 编译器默认写法
		m_height = new int(*p.m_height)
	}

|| 构造函数的初始化列表:(类的另一种初始化方式)

	//Person(int a, int b) : p_A(a), p_B(b)  {}
	Person(int a, int b){
		p_A = a;
		p_B = b;
	}

|| 当一个类的对象作为一个类的属性时:

	构造顺序:先支类再主类
	析构顺序:先主类再支类(相反)

限定符

//先介绍一下this指针
|| this指针是指向调用该函数的对象的指针

|| this指针的本质:是一个指针常量(指针的指向不可以改变,即只可以指向调用函数的对象)

	用处:
	1,防止名称冲突。this -> age = age;
	2,*this 可以让函数返回对象本身。   
		
		//tips:this 返回值必须是Person的引用,防止创造新的对象的副本
		Person & addPersonAge (Person p)
		{	
			......
			return *this;
		}

static

|| 静态成员变量 static — 内存固定在一处的变量 (改变数据以后就会一致使用新数据)静态成员变量不被一个对象专有,而是所有的该类对象共享

  静态成员变量的特点
      1,所有对象共享同一份数据
      2,类内声明,类外初始化      
 	  // 3,在编译阶段分配内存(全局区)

|| 静态成员函数 static — 一种针对静态变量进行操作的函数,针对固定内存的变量进行操作的函数 静态成员函数不被一个对象专有,而是所有的该类对象共享

	静态成员函数的特点
	 	1,所有对象共享同一个函数
		2,静态成员函数只能访问静态成员变量

|| 只有非静态成员变量才储存在类上;非静态成员函数和静态成员都不出存在类上

const

|| const 修饰成员变量 ------ 常数 ------ 将数据设置为只读状态

	const m_Age;

|| const 修饰成员函数 ------ 常函数 — 函数将不可修改成员属性的值

	本质上是修饰该函数的 this指针,使之变成常量指针  (最终变成了常量指针常量)
	void addPersonAge() const {
	}

|| const 修饰变量 ------------ 常对象 ----对象将不可修改成员属性

		常对象实际上就是常函数加常数的结合
		const Person p1;	

|| 常对象只能调用常函数,不用调用普通成员函数

|| mutable 修饰的成员变量无论何时何地都可以修改 (mutable — 易变的)

friend
友元(就是友元函数/友元类) 让一个函数或者类变成某个类的朋友,访问另一个类中私有成员

友元的三种实现
	1,全局函数做友元
	2,类做友元
    3,成员函数做友元

class Building
{
	// 告诉编译器 goodGay全局函数 是 Building类的好朋友
	// friend + 函数声明
	1,friend void goodGay(Building * building);
	2,friend class Person
	3,friend void Person::add() 

public:

private:
}

运算符重载

实质上是构造 特殊函数operator 这个函数有特殊的调用方式,可以被简化为运算符形式

//一般可以使用成员函数或者全局函数进行重载
简化:Preson p3 = p1 + p2    ---  Person P3 = p1.operator+(p2)  --- 成员函数
							 --- Person P3 = Operator(p1, p2)   --- 全局函数

|| 算数运算符重载
示例

	//成员operator函数 实现+运算符重载
	Person operator+(const Person& p) {
		Person temp;
		temp.m_A = this->m_A + p.m_A;
		temp.m_B = this->m_B + p.m_B;
		return temp;
	}
	
	//全局operator函数 实现+运算符重载
	Person operator+(const Person& p2, int val)  
	{
		Person temp;
		temp.m_A = p2.m_A + val;
		temp.m_B = p2.m_B + val;
		return temp;
	}

|| 左移运算符<< 的重载

注意事项:1,ostream为输出流类
		  2,传入输出流参数时,因为cout全局中只能有一个,所以必须使用(别名)
		  3,为了达到cout << p 的实际效果,只能使用全局函数重构(成员函数 p<<cout)
		  4,为了达到cout <<p<< endl的实际效果,必须返回一个输出流(链式编程思想)
ostream& operator<< (ostream &cout, Person &p) {
	
	cout << "m_A = " << p.m_A << "m_B = " << p.m_B;
	
	return cout;
}

|| 递增运算符

注意事项:
		  前置递增和后置递增的区分:
		  一:函数名称上
		  	前置递增运算符对应的函数  operator++()
		  	后置递增运算符对应函数 operator+(int)  ---系统会懂
		  二: 功能实现上
		  	前置递增先实现++ 后 return
		  	后置递增先记录当前值 后实现++ 最后返回原记录值
		  三:返回类型上
		 	前置:必须返回别名!保持只对同一个数操作
		 	后置:必须返回值!因为已经通过局部对象记录过了值,且局部对象会被释放
//前置++
	MyInteger& operator++() {
		//先++
		m_Num++;
		//再返回
		return *this;
	}

	//后置++
	MyInteger operator++(int) {
		//先返回
		MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;
		m_Num++;
		return temp;
	}

|| 类的赋值运算符的重载

注意事项:
同样,在涉及内存释放问题时,对象的赋值操作也会有深拷贝和浅拷贝的问题(同拷贝构造)

|| 赋值中的深拷贝操作:1,判断成员变量是否在堆区中,并清空 2,重新new
|| 复习:拷贝构造中的深拷贝操作:只需new来开辟内存存放变量(未构造无需清空)

class Person{
int *m_A
public:
	Person(int a){
		m_A = new int(a);
	}	

	Person operator=(Person p){
		// 1,先判断本对象是否在堆区有内存
		if(*m_A != NULL)
		{
			delete m_A;
			m_A == NULL;
		}
		
		// 2,深拷贝   在堆区重新开辟内存
		m_A = new int(*p.m_A);
		return *this;
	}
}

|| 关系运算符的重载

bool operator==(Person & p)
bool operator!=(Person & p)
bool operator>=(Person & p)

|| 函数调用符()的重载

|| 由于重构后的 对象() 使用起来特别想像一个函数调用函数(),故也称作 — 仿函数

class MyPrint
{
public:
	void operator()(string text)
	{
		cout << text << endl;
	}

};

|| 匿名对象写法:类名() — 自动创建一个对象,并在该行结束后立刻被释放

发布了24 篇原创文章 · 获赞 40 · 访问量 3949

猜你喜欢

转载自blog.csdn.net/a13352912632/article/details/104176531