0
点赞
收藏
分享

微信扫一扫

2022-1-4 类

类中的 属性和行为 统一称为成员
属性 又称为 成员属性 成员变量
行为 成员函数 成员方法

一 &&&&&&&封装&&&&&&&

1 圆类

//&&&&&&&&&&&&&&&&&&&&&& 1.封装
// 设计一个圆类,求圆的周长
//周长:2*pi*R
class Circle
{
	//访问权限
public:

	//属性
	int m_r;

	//行为
	//获取圆的周长
	double claculateZC()
	{
		return 2 * 3.14 * m_r;
	}
};


int main()
{
	Circle C1;

	C1.m_r = 10;

	cout << "zc is " << C1.claculateZC() << endl;
	return 0;
}

2 学生类

#include <stdio.h>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std
 案例2 :学生类
class Student
{
public:
	int m_num;
	string m_name;

	void Show()
	{
		cout << "ID: " << m_num << endl;
		cout << "name : " << m_name << endl;
	}

	void setName(string name)
	{
		m_name = name;
	}
};

int main()
{
	Student s1;
	s1.m_num = 1;
	s1.setName("zhangsan");
	s1.Show();


	Student s2;
	s2.m_num = 2;
	s2.m_name = "lisi";
	s2.Show();
	return 0;
}

3 访问权限

//访问权限
//三种
//公共权限 成员 类内可以访问 ,类外可以访问
//保护权限 成员 类内可以访问 ,类外不可以访问 ,儿子可以访问父亲的保护内容
//私有权限 成员 类内可以访问 ,类外不可以访问 ,儿子不可以访问父亲的私有内容

所谓不能访问,是指不仅仅不能修改,连调用都不可以

4. struct 和 class 的区别 ,唯一的区别是默认的访问权限是不同的

// struct 和 class 的区别
//唯一的区别是默认的访问权限是不同的
//struct默认的访问权限是公有
//class 默认的访问权限是私有

class C1
{
	int m_a;

};

struct C2
{
	int m_a;
};


int main()
{
	C1 c1;
	//c1.m_a = 100; //不可访问

	C2 c2;
	c2.m_a = 100;
	return 0;
}

5 成员设置为私有的好处

//成员设置为私有的好处
//1.可以控制读写权限


class Person
{

public:
	//姓名原本是私有,类外根本访问不到,通过函数接口,来间接的修改
	void setName(string name)  //写
	{
		m_name = name;
	}

	string getName() //读
	{
		return m_name;
	}


	//希望年龄是只读,那就只提供给一个读的接口
	int getAge() //读
	{
		m_age = 20;
		return m_age;
	}

	void setLover(string lover)
	{
		m_lover = lover;
	}

private:
	//可以自行设置权限
	string m_name;
	int m_age;
	string m_lover;

};

int main()
{
	Person p1;
	p1.setName("zhangsan");
	cout << "name = " << p1.getName() << endl;

	cout << "age = " << p1.getAge() << endl;

	p1.setLover("baby");
	return 0;
}

6. 案例1 立方体类

// 案例 :立方体
//求出立方体的面积和体积
//分别用全局函数和成员函数来判断两个立方体是否相等

class Cube
{

public:
	void setWidth(int width)
	{
		m_width = width;
	}
	int getWidth()
	{
		return m_width;
	}

	void setHeight(int height)
	{
		m_height = height;
	}
	int getHeight()
	{
		return m_height;
	}

	void setLenght(int length)
	{
		m_lenght = length;
	}
	int getLenght()
	{
		return m_lenght;
	}

	int getArea()
	{
		return 2 * (m_width * m_height + m_width * m_lenght + m_lenght * m_height);
	}

	int getVolumn()
	{
		return m_width * m_height * m_lenght;
	}

	bool isSame(Cube c2)
	{
		if (c2.getHeight() == m_height && c2.getLenght() == m_lenght && c2.getWidth() == m_width)
			return true;
		else
			return false;
	}

private:
	int m_width;
	int m_height;
	int m_lenght;

};


bool isSameOrNot(Cube c1, Cube c2)
{
	if (c2.getHeight() == c1.getHeight() && c2.getLenght() == c1.getLenght() && c2.getWidth() == c1.getWidth())
		return true;
	else
		return false;
}

int main()
{
	Cube c1;
	c1.setHeight(10);
	c1.setLenght(10);
	c1.setWidth(10);

	cout << "the area : " <<  c1.getArea() << endl;
	cout << "the volumn : " << c1.getVolumn() << endl;

	Cube c2;
	c2.setHeight(10);
	c2.setLenght(10);
	c2.setWidth(10);

	cout << "************ 全局函数判断两个立方体是否一样" << endl;
	bool ret = isSameOrNot(c1, c2);
	if (ret)
	{
		cout << "same" << endl;
	}
	else
	{
		cout << "not same" << endl;
	}


	cout << "************ 成员函数判断两个立方体是否一样" << endl;
	bool ret1 = c1.isSame(c2);
	if (ret)
	{
		cout << "same" << endl;
	}
	else
	{
		cout << "not same" << endl;
	}
	return 0;
}

7 案例2 圆和点的位置关系 一个类可以作为另一个类的成员

//案例:判断点和圆的关系

class Point
{
public:
	void setX(int x)
	{
		m_x = x;
	}
	double getX()
	{
		return m_x;
	}

	void setY(int y)
	{
		m_y = y;
	}
	double getY()
	{
		return m_y;
	}
private:
	double m_x;
	double m_y;
};

class Circle
{
public:
	void setR(int r)
	{
		m_r = r;
	}
	double getR()
	{
		return m_r;
	}

	void setCenter(Point center)
	{
		m_center = center;
	}
	Point getCenter()
	{
		return m_center;
	}

public:
	void judgeRelation()
	{

	}

private:
	double m_r;
	Point  m_center;  //这里其实就是创建了一个点的类对象
};

void isInCircle(Circle &c ,Point &p)
{
	int distance;
	distance = (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
		(c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
    
	int rSquare = c.getR() * c.getR();

	if (distance > rSquare)
	{
		cout << "out" << endl;
	}
	else if (distance < rSquare)
	{
		cout << "in" << endl;
	}
	else
	{
		cout << "on" << endl;
	}
}

int main()
{
	Circle c;
	c.setR(10);

	Point center;
	center.setX(10);
	center.setY(0);
	c.setCenter(center);

	Point p;
	p.setX(10);
	p.setY(20);
	isInCircle(c, p);

	return 0;
}

二 对象特性

1.构造函数和析构函数实现类的初始化和清理

在这里插入图片描述

class Person
{
public:
	//1.构造函数实现初始化  
	Person()
	{
		cout << "构造函数" << endl;
	}

	//2.析构函数实现清理
	~Person()
	{
		cout << "析构函数" << endl;
	}
};

int main()
{
	Person p1;  
	return 0;
}

2.构造函数的分类和调用

//
//1分类
//按照参数分类  无参构造函数(默认构造) 和 有参构造函数
//按照类型分类  拷贝构造 普通构造

class Person
{
public:

	Person()
	{
		cout << "无参构造函数" << endl;
	}

	Person(int a)
	{
		m_age = a;
		cout << "有参构造函数" << endl;
	}

	//拷贝构造
	Person(const Person &p)
	{
		//将传入的人的所有属性,拷贝到当前的类中
		m_age = p.m_age;
		cout << "拷贝构造" << endl;
	}


    ~Person()
	{
		cout << "析构函数" << endl;
	}

	int m_age;
};


//构造函数的调用
void test()
{

	Person p1;  //什么都不做,就会调用默认构造函数
	//注意1,调用默认构造的时候不要写(),不会执行任何东西,因为编译器会认为下面语句是一个函数声明,不会认为在创建对象
	//Person p();
	//void func(); 两者类似,可以认为上面一行语句是函数声明

	//1.括号法
	Person p2(10);  //括号法调用有参构造函数
	Person p3(p2);  //括号法调用拷贝构造函数

	cout << "p2 age is " << p2.m_age << endl;
	cout << "p3 age is " << p3.m_age << endl;

	//2.显示法
	Person p4 = Person(10);  //显示法调用有参构造函数
	Person p5 = Person(p4);  //显示法调用有拷贝构造函数

	//注意2:单独的一个语句 Person (10); 左侧没有接收,称为匿名对象,匿名对象的特点是当前行执行结束之后,系统立即释放
	//注意3:不要用拷贝构造函数来初始化一个匿名对象
	         //Person(p5);  运行显示 Person p5重定义  因为 Person(p5) === Person p5,是一对象声明

	//3.隐式转换法
	Person p6 = 100;   //相等于 Person p6 = Person(10);
	Person p7 = p6;   //隐式转换法 调用拷贝构造函数
}
int main()
{
	test();
	return 0;
}```


## 3.拷贝构造函数的使用时机

```cpp
//拷贝构造函数的调用时机
class Person
{
public:

	Person()
	{
		cout << "无参构造函数" << endl;
	}

	Person(int a)
	{
		m_age = a;
		cout << "有参构造函数" << endl;
	}

	
	//拷贝构造
	Person(const Person &p)
	{
		//将传入的人的所有属性,拷贝到当前的类中
		m_age = p.m_age;
		cout << "拷贝构造" << endl;
	}


    ~Person()
	{
		cout << "析构函数" << endl;
	}

	int m_age;
};

//1.使用一个已经创建完毕的对象来初始化一个新的对象
void test()
{
	Person p1(20);
	Person p2(p1);
}

//2.值传递的方式给函数参数传值
void doWork(Person p)
{
}
void test02()
{
	Person p;
	doWork(p);//形参传值给实参是拷贝之后才传递的
}


//3.值方式返回局部对象
Person doWork2()
{
	Person p;  //局部变量,函数调用结束就释放了
	return p;   //但是这里return 的是p的副本,调用了拷贝的新的p,不是创建的对象本身
}
void test03()
{
	Person p = doWork2();
}

int main()
{
	test03();
	return 0;
}

在这里插入图片描述

3 构造函数的调用规则

//构造函数的调用规则
//默认情况下,c++会至少给一个类添加3个函数
//1.默认提供一个无参构造函数
//2.默认提供一个无参析构
//3.默认提供拷贝构造,对属性进行值拷贝

4 深拷贝与浅拷贝

1.浅拷贝

class Person
{
public:
	
		Person()
		{
			cout << "无参构造函数" << endl;
		}
	
		Person(int age ,int height)
		{
			m_age = age;
			m_height = new int(height);
			cout << "有参构造函数" << endl;
		}
	
		//拷贝构造
		Person(const Person &p)
		{
			//将传入的人的所有属性,拷贝到当前的类中
			m_age = p.m_age;
			cout << "拷贝构造" << endl;
		}
	
	
	    ~Person()
		{
			if (m_height != NULL)
			{
				delete m_height;
				m_height = NULL;
			}
			cout << "析构函数" << endl;
		}
	
		int m_age;
		int* m_height;  //将这个数据开辟再堆区
};


void test01()
{
	Person p(18, 160);

	cout << "p.age = " << p.m_age << " p.m_height= " << *p.m_height << endl;

	Person p1(p);

	cout << "p1.age = " << p1.m_age  << " p1.m_height= " << *p1.m_height << endl;
}

int main()
{
	test01();
	return 0;
}

上面的程序回报错,显示地址冲突,原因如下:

浅拷贝存在的问题,栈内的数据,先进后出,如果先创建了P1类对象,然后创建了P2类对象,那么在程序执行完之后,类会自己调用析构函数,释放开辟的栈区的内存空间,调用析构的时候,先调用的是P2的析构,后进先出。

但是由于浅拷贝,是完全的将一个类里面的东西,包括地址完全的拷贝过来。在释放的时候,P2先释放,将存放m_height的地址空间先释放了,然后P1回再一次调用析构释放他的内存空间,但是这个内存空间已经被释放了,在这里又对同一个内存空间重复释放
在这里插入图片描述

2.深拷贝
什么时候需要用到深拷贝:
当在堆区创建数据时,就需要自己来提供一个深拷贝的拷贝函数

	    //自己实现拷贝构造,解决浅拷贝的问题,也就是深拷贝,开辟一个新的内存,来存放堆区的数据
		Person(const Person& p)
		{
			m_age = p.m_age;
			m_height = new int(*p.m_height);
			cout << "拷贝构造" << endl;
		}

5 初始化列表也可以实现属性的初始化

1.传统的初始化操作,在构造函数中初始化

class Person
{
public:
	
	Person(int a, int b, int c)
	{
		m_a = a;
		m_b = b;
		m_c = c;
	}

	int m_a;
	int m_b;
	int m_c;
};

2.列表初始化

class Person
{
public:
	Person(int a,int b,int c) :m_a(a), m_b(b), m_c(c)
	{
	}
	
	int m_a;
	int m_b;
	int m_c;
};

6 一个类作为另一个类的成员

class Phone
{
public:
	Phone(string pName)
	{
		m_phoneName = pName;
	}
	string m_phoneName;
};

class Person
{
public:
	Person(string name,string pName):m_name(name), m_phone(pName)
	{
	}

	string m_name;
	Phone m_phone;
};

void test()
{
	Person p("zhang san ", "max");
	cout << p.m_name << " have " << p.m_phone.m_phoneName << endl;
}


int main()
{
	test();
	return 0;
}

7 静态成员函数 和静态成员变量 的调用

//静态成员函数
//静态成员函数只能访问静态成员变量
//因为静态成员函数在类里面只有1个,也就是无论你创建多少个类对象,p1,p2,…,所有的类对象是共享这一个静态成员函数的,不会各自创建一个
//静态成员函数,所以,如果你在静态成员函数里面对非静态变量进行操作,非静态成员变量,是属于某一个特定的类对象的属性
//在静态成员函数里面,是无法区分谁是谁的,数据是共享的,两者矛盾,也就是无法区分静态成员函数里面操作的是哪一个类对象的
//成员

class Person
{
public:
	static void func()
	{
		m_A = 100;
		//m_b = 200;  报错,静态成员函数不能访问非静态的成员变量
		cout << "static void func() " << endl;
	}

	static int m_A; //静态成员变量
	int m_b;
};

//静态成员变量,需要在类内访问,类外声明
int Person::m_A = 0;

void test()
{
	//静态函数的访问,方法1,通过对象访问
	Person p;
	p.func();

	//静态函数的访问,方法2,通过类名访问
	Person::func();
}

int main()
{
	test();
	return 0;
}

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

如何理解这里的分开存储:
也就是说,只有非静态的成员变量是属于类对象的,是和类本身放在一起存储的,打印类的大小时,静态成员函数,静态成员变量,以及成员函数,都对类的大小时没有贡献的。

另外:空类的大小是1,不是0,是因为如果创建多个空类,编译器需要将这些空类放在不同的地址空间,即使是空类,也要避免存放在同一块内存

9 this指针的理解和应用

1.作用1:
前面说了,静态成员函数,只有一份,不会随着创建类的增多,而创建,那么编译器如何区分是谁在调用这共用的函数,就是通过this指针来区分的

2.作用2:
成员函数里面的形参和成员变量同名的时候,可用this来解决

以下程序是运行异常的

class Person
{
public:
	Person(int age)
	{
		age = age;
	}

	int age;
};

void test()
{
	Person p(18);
	cout << " age = " << p.age << endl;
}

int main()
{
	test();
	return 0;
}

可修改为

class Person
{
public:
	Person(int age)
	{
	//this指针指向的是 被调用的成员函数 对应的对象
		this->age = age;
	}

	int age;
};

void test()
{
	Person p(18);
	cout << " age = " << p.age << endl;
}

int main()
{
	test();
	return 0;
}

3.作用3:
可用于返回对象本身

#include <stdio.h>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;



&&&&&&&&&&&&&&&&&&&&&& 1.封装

 案例1 :设计一个圆类,求圆的周长

周长:2*pi*R
//class Circle
//{
//	//访问权限
//public:
//
//	//属性
//	int m_r;
//
//	//行为
//	//获取圆的周长
//	double claculateZC()
//	{
//		return 2 * 3.14 * m_r;
//	}
//};
//
//
//int main()
//{
//	Circle C1;
//
//	C1.m_r = 10;
//
//	cout << "zc is " << C1.claculateZC() << endl;
//	return 0;
//}

 案例2 :学生类

//class Student
//{
//public:
//	int m_num;
//	string m_name;
//
//	void Show()
//	{
//		cout << "ID: " << m_num << endl;
//		cout << "name : " << m_name << endl;
//	}
//
//	void setName(string name)
//	{
//		m_name = name;
//	}
//};
//
//int main()
//{
//	Student s1;
//	s1.m_num = 1;
//	s1.setName("zhangsan");
//	s1.Show();
//
//
//	Student s2;
//	s2.m_num = 2;
//	s2.m_name = "lisi";
//	s2.Show();
//	return 0;
//}

//访问权限
//三种 
//公共权限 成员  类内可以访问 ,类外可以访问
//保护权限 成员  类内可以访问 ,类外不可以访问 ,儿子可以访问父亲的保护内容
//私有权限 成员  类内可以访问 ,类外不可以访问 ,儿子不可以访问父亲的私有内容


// struct 和 class 的区别
//唯一的区别是默认的访问权限是不同的
//struct默认的访问权限是公有
//class 默认的访问权限是私有

//class C1
//{
//	int m_a;
//
//};
//
//struct C2
//{
//	int m_a;
//};
//
//
//int main()
//{
//	C1 c1;
//	//c1.m_a = 100; //不可访问
//
//	C2 c2;
//	c2.m_a = 100;
//	return 0;
//}


//成员设置为私有的好处
//1.可以控制读写权限


//class Person
//{
//
//public:
//	//姓名原本是私有,类外根本访问不到,通过函数接口,来间接的修改
//	void setName(string name)  //写
//	{
//		m_name = name;
//	}
//
//	string getName() //读
//	{
//		return m_name;
//	}
//
//
//	//希望年龄是只读,那就只提供给一个读的接口
//	int getAge() //读
//	{
//		m_age = 20;
//		return m_age;
//	}
//
//	void setLover(string lover)
//	{
//		m_lover = lover;
//	}
//
//private:
//	//可以自行设置权限
//	string m_name;
//	int m_age;
//	string m_lover;
//
//};
//
//int main()
//{
//	Person p1;
//	p1.setName("zhangsan");
//	cout << "name = " << p1.getName() << endl;
//
//	cout << "age = " << p1.getAge() << endl;
//
//	p1.setLover("baby");
//	return 0;
//}


// 案例 :立方体
//求出立方体的面积和体积
//分别用全局函数和成员函数来判断两个立方体是否相等

//class Cube
//{
//
//public:
//	void setWidth(int width)
//	{
//		m_width = width;
//	}
//	int getWidth()
//	{
//		return m_width;
//	}
//
//	void setHeight(int height)
//	{
//		m_height = height;
//	}
//	int getHeight()
//	{
//		return m_height;
//	}
//
//	void setLenght(int length)
//	{
//		m_lenght = length;
//	}
//	int getLenght()
//	{
//		return m_lenght;
//	}
//
//	int getArea()
//	{
//		return 2 * (m_width * m_height + m_width * m_lenght + m_lenght * m_height);
//	}
//
//	int getVolumn()
//	{
//		return m_width * m_height * m_lenght;
//	}
//
//	bool isSame(Cube c2)
//	{
//		if (c2.getHeight() == m_height && c2.getLenght() == m_lenght && c2.getWidth() == m_width)
//			return true;
//		else
//			return false;
//	}
//
//private:
//	int m_width;
//	int m_height;
//	int m_lenght;
//
//};
//
//
//bool isSameOrNot(Cube c1, Cube c2)
//{
//	if (c2.getHeight() == c1.getHeight() && c2.getLenght() == c1.getLenght() && c2.getWidth() == c1.getWidth())
//		return true;
//	else
//		return false;
//}
//
//int main()
//{
//	Cube c1;
//	c1.setHeight(10);
//	c1.setLenght(10);
//	c1.setWidth(10);
//
//	cout << "the area : " <<  c1.getArea() << endl;
//	cout << "the volumn : " << c1.getVolumn() << endl;
//
//	Cube c2;
//	c2.setHeight(10);
//	c2.setLenght(10);
//	c2.setWidth(10);
//
//	cout << "************ 全局函数判断两个立方体是否一样" << endl;
//	bool ret = isSameOrNot(c1, c2);
//	if (ret)
//	{
//		cout << "same" << endl;
//	}
//	else
//	{
//		cout << "not same" << endl;
//	}
//
//
//	cout << "************ 成员函数判断两个立方体是否一样" << endl;
//	bool ret1 = c1.isSame(c2);
//	if (ret)
//	{
//		cout << "same" << endl;
//	}
//	else
//	{
//		cout << "not same" << endl;
//	}
//	return 0;
//}


//案例:判断点和圆的关系

//class Point
//{
//public:
//	void setX(int x)
//	{
//		m_x = x;
//	}
//	double getX()
//	{
//		return m_x;
//	}
//
//	void setY(int y)
//	{
//		m_y = y;
//	}
//	double getY()
//	{
//		return m_y;
//	}
//private:
//	double m_x;
//	double m_y;
//};
//
//class Circle
//{
//public:
//	void setR(int r)
//	{
//		m_r = r;
//	}
//	double getR()
//	{
//		return m_r;
//	}
//
//	void setCenter(Point center)
//	{
//		m_center = center;
//	}
//	Point getCenter()
//	{
//		return m_center;
//	}
//
//public:
//	void judgeRelation()
//	{
//
//	}
//
//private:
//	double m_r;
//	Point  m_center;  //这里其实就是创建了一个点的类对象
//};
//
//void isInCircle(Circle &c ,Point &p)
//{
//	int distance;
//	distance = (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
//		(c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
//    
//	int rSquare = c.getR() * c.getR();
//
//	if (distance > rSquare)
//	{
//		cout << "out" << endl;
//	}
//	else if (distance < rSquare)
//	{
//		cout << "in" << endl;
//	}
//	else
//	{
//		cout << "on" << endl;
//	}
//}
//
//int main()
//{
//	Circle c;
//	c.setR(10);
//
//	Point center;
//	center.setX(10);
//	center.setY(0);
//	c.setCenter(center);
//
//	Point p;
//	p.setX(10);
//	p.setY(20);
//	isInCircle(c, p);
//
//	return 0;
//}

//*************************   对象特性 
//1.构造和析构


//class Person
//{
//public:
//	//1.构造函数实现初始化  
//	Person()
//	{
//		cout << "构造函数" << endl;
//	}
//
//	//2.析构函数实现清理
//	~Person()
//	{
//		cout << "析构函数" << endl;
//	}
//};
//
//int main()
//{
//	Person p1;  
//	return 0;
//}


构造函数的分类和调用

1分类
按照参数分类  无参构造函数(默认构造) 和 有参构造函数
按照类型分类  拷贝构造 普通构造
//
//class Person
//{
//public:
//
//	Person()
//	{
//		cout << "无参构造函数" << endl;
//	}
//
//	Person(int a)
//	{
//		m_age = a;
//		cout << "有参构造函数" << endl;
//	}
//
//	//拷贝构造
//	Person(const Person &p)
//	{
//		//将传入的人的所有属性,拷贝到当前的类中
//		m_age = p.m_age;
//		cout << "拷贝构造" << endl;
//	}
//
//
//    ~Person()
//	{
//		cout << "析构函数" << endl;
//	}
//
//	int m_age;
//};
//
//
构造函数的调用
//void test()
//{
//
//	Person p1;  //什么都不做,就会调用默认构造函数
//	//注意1,调用默认构造的时候不要写(),不会执行任何东西,因为编译器会认为下面语句是一个函数声明,不会认为在创建对象
//	//Person p();
//	//void func(); 两者类似,可以认为上面一行语句是函数声明
//
//	//1.括号法
//	Person p2(10);  //括号法调用有参构造函数
//	Person p3(p2);  //括号法调用拷贝构造函数
//
//	cout << "p2 age is " << p2.m_age << endl;
//	cout << "p3 age is " << p3.m_age << endl;
//
//	//2.显示法
//	Person p4 = Person(10);  //显示法调用有参构造函数
//	Person p5 = Person(p4);  //显示法调用有拷贝构造函数
//
//	//注意2:单独的一个语句 Person (10); 左侧没有接收,称为匿名对象,匿名对象的特点是当前行执行结束之后,系统立即释放
//	//注意3:不要用拷贝构造函数来初始化一个匿名对象
//	         //Person(p5);  运行显示 Person p5重定义  因为 Person(p5) === Person p5,是一对象声明
//
//	//3.隐式转换法
//	Person p6 = 100;   //相等于 Person p6 = Person(10);
//	Person p7 = p6;   //隐式转换法 调用拷贝构造函数
//}
//int main()
//{
//	test();
//	return 0;
//}


//构造函数的调用规则
//默认情况下,c++会至少给一个类添加3个函数
//1.默认提供一个无参构造函数
//2.默认提供一个无参析构
//3.默认提供拷贝构造,对属性进行值拷贝


深拷贝和浅拷贝

//class Person
//{
//public:
//	
//		Person()
//		{
//			cout << "无参构造函数" << endl;
//		}
//	
//		Person(int age ,int height)
//		{
//			m_age = age;
//			m_height = new int(height);
//			cout << "有参构造函数" << endl;
//		}
//	
//		拷贝构造
//		//Person(const Person &p)
//		//{
//		//	//将传入的人的所有属性,拷贝到当前的类中
//		//	m_age = p.m_age;
//		//	cout << "拷贝构造" << endl;
//		//}
//	
//	    //自己实现拷贝构造,解决浅拷贝的问题,也就是深拷贝,开辟一个新的内存,来存放堆区的数据
//		Person(const Person& p)
//		{
//			m_age = p.m_age;
//			m_height = new int(*p.m_height);
//			cout << "拷贝构造" << endl;
//		}
//
//
//	    ~Person()
//		{
//			if (m_height != NULL)
//			{
//				delete m_height;
//				m_height = NULL;
//			}
//			cout << "析构函数" << endl;
//		}
//	
//		int m_age;
//		int* m_height;  //将这个数据开辟再堆区
//};
//
//
//void test01()
//{
//	Person p(18, 160);
//
//	cout << "p.age = " << p.m_age << " p.m_height= " << *p.m_height << endl;
//
//	Person p1(p);
//
//	cout << "p1.age = " << p1.m_age  << " p1.m_height= " << *p1.m_height << endl;
//}
//
//int main()
//{
//	test01();
//	return 0;
//}


//初始化列表也可以实现属性的初始化

//class Person
//{
//public:
//	// 传统的初始化操作,在构造函数中初始化
//	//Person(int a, int b, int c)
//	//{
//	//	m_a = a;
//	//	m_b = b;
//	//	m_c = c;
//	//}
//
//	Person(int a,int b,int c) :m_a(a), m_b(b), m_c(c)
//	{
//	}
//
//
//	int m_a;
//	int m_b;
//	int m_c;
//};
//
void test01()
{
	Person p(10, 20, 30);
	cout << "m_a = " << p.m_a << endl;
	cout << "m_b = " << p.m_b << endl;
	cout << "m_c = " << p.m_c << endl;
}
//
//void test02()
//{
//	Person p;
//	cout << "m_a = " << p.m_a << endl;
//	cout << "m_b = " << p.m_b << endl;
//	cout << "m_c = " << p.m_c << endl;
//}
//
//int main()
//{
//	test02();
//	return 0;
//}

//一个类作为另一个类的成员

//class Phone
//{
//public:
//	Phone(string pName)
//	{
//		m_phoneName = pName;
//	}
//	string m_phoneName;
//};
//
//class Person
//{
//public:
//	Person(string name,string pName):m_name(name), m_phone(pName)
//	{
//	}
//
//	string m_name;
//	Phone m_phone;
//};
//
//void test()
//{
//	Person p("zhang san ", "max");
//	cout << p.m_name << " have " << p.m_phone.m_phoneName << endl;
//}
//
//
//int main()
//{
//	test();
//	return 0;
//}

//静态成员函数
//静态成员函数只能访问静态成员变量
//因为静态成员函数在类里面只有1个,也就是无论你创建多少个类对象,p1,p2,...,所有的类对象是共享这一个静态成员函数的,不会各自创建一个
//静态成员函数,所以,如果你在静态成员函数里面对非静态变量进行操作,非静态成员变量,是属于某一个特定的类对象的属性
//在静态成员函数里面,是无法区分谁是谁的,数据是共享的,两者矛盾,也就是无法区分静态成员函数里面操作的是哪一个类对象的
//成员

//class Person
//{
//public:
//	static void func()
//	{
//		m_A = 100;
//		//m_b = 200;  报错,静态成员函数不能访问非静态的成员变量
//		cout << "static void func() " << endl;
//	}
//
//	static int m_A; //静态成员变量
//	int m_b;
//};
//
静态成员变量,需要在类内访问,类外声明
//int Person::m_A = 0;
//
//void test()
//{
//	//静态函数的访问,方法1,通过对象访问
//	Person p;
//	p.func();
//
//	//静态函数的访问,方法2,通过类名访问
//	Person::func();
//}
//
//int main()
//{
//	test();
//	return 0;
//}


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

class Person
{
public:
	Person(int age)
	{
		this->age = age;
	}

	void PersonAddAge(Person &p)
	{
		//将传进来的数据加到自身上
		this->age = this->age + p.age;
	}

	Person& PersonAddAge2(Person& p)
	{
		//将传进来的数据加到自身上
		this->age = this->age + p.age;
		//this是指向对象的指针,*this就是解引用
		//return *this; 返回对象本身
		return *this;
	}


	Person PersonAddAge3(Person& p)
	{
		//将传进来的数据加到自身上
		this->age = this->age + p.age;
		//this是指向对象的指针,*this就是解引用
		//return *this; 返回对象本身
		return *this;
	}

	int age;
};

void test()
{
	Person p1(18);
	cout << " p1 age = " << p1.age << endl;

	Person p2(20);
	p2.PersonAddAge(p1);  //成员函数返回值类型是void,所以这个操作只能执行一次
	cout << " p2 age = " << p2.age << endl;

	Person p3(10);
	p3.PersonAddAge2(p1).PersonAddAge2(p1).PersonAddAge2(p1); //成员函数返回值类型是类对象本身,所以这个操作能无限执行
	cout << " p3 age = " << p3.age << endl;

	Person p4(10);
	p4.PersonAddAge3(p1).PersonAddAge3(p1).PersonAddAge3(p1); //成员函数返回值类型是类对象本身,所以这个操作能无限执行
	cout << " p4 age = " << p4.age << endl;
}

int main()
{
	test();
	return 0;
}

p4为什么是10,没有实现累加,是因为:
Person PersonAddAge3(Person& p)
{
this->age = this->age + p.age;
return *this;
}
这里返回类对象,不是类本身,就会调用拷贝构造函数,拷贝构造函数的本质的,创建一个新的类对象,来存放一模一样的数据,也就是说,return的已经不是类对象本身了,而是一个新的类,一个存放了和当前类数据一摸一样的新类,所以
p4.PersonAddAge3(p1).PersonAddAge3(p1).PersonAddAge3(p1);
p4.PersonAddAge3(p1)执行结束后,做了一次累加,返回的类已经不是p4了,所以打印的值只是p4做了一次累加的结果

在这里插入图片描述

上述案例,如果返回的
在这里插入图片描述

10 为了防止空指针对象访问成员属性,可以再函数里面加一个if判断,防止程序出错

//空指针访问成员函数
class Person
{
public:
	void showClassNmae()
	{
		cout << " showClassNmae() " << endl;
	}

	void showAge()
	{
		if (this == NULL)
		{
			return;
		}
		cout << "age = " << this->m_age << endl;
	}

	int m_age;
};


void test()
{
	Person* p = NULL;  //创建一个空指针


	p->showClassNmae(); // 能正常执行

	p->showAge(); //报错,显示地址冲突
}

int main()
{
	test();
	return 0;
}

11 const 修饰成员函数(常函数),const 成员属性(常变量),const 修饰对象(常对象)

//const 修饰成员函数
//常函数里面的对象是不可以修改的
class Person
{
public:

	//常函数
	//this指针的本质,是指针常量,指针的指向是不可以修改的
	//在成员函数后面加 const,函数变成常函数,这个const修饰的是this指针,使得thsi指针指向的值也不能修改
	void showPerson() const
	{
		//this->m_a = 100;   报错,表达式必须是可修改的左值 指针指向的值不可以修改
		this->m_b = 100;
	}

	void fun()
	{
	}

	int m_a;
	mutable int m_b;  //常变量,即使在常函数中也可以修改这个变量
};


//常对象
void test()
{
	const Person p;
	//p.m_a = 100;  报错,常函数和常对象都只能操作常变量,且常对象只能调用常函数
	p.m_b = 100;  
	p.showPerson();
}

int main()
{
	test();
	return 0;
}

三 友元

1.全局函数做友元 (所谓全局函数,就是常规的定义在main函数外面的函数)

//全局函数做友元
class Building
{
	//goodGay函数是 Building的好朋友,可以访问类内的私有成员
	friend void goodGay(Building* building);
public:
	Building()
	{
		m_sittingRoom = "客厅";
		m_bedRoom = "卧室";
	}

	string m_sittingRoom;

private:
	string m_bedRoom;
};


//全局函数
//所谓全局函数,就是放在main函数外面的函数
void goodGay(Building *building)
{
	cout << "全局函数goodGay is visting :" << building->m_sittingRoom << endl;

	cout << "全局函数goodGay is visting :" << building->m_bedRoom << endl;
}

int main()
{
	Building b;
	goodGay(&b);
	return 0;
}

2 类做友元 以及 在类外实现成员函数

(1)类做友元

class Building
{

	//goodGay函数是 Building的好朋友,可以访问类内的私有成员
	friend class GoodGay;

public:
	Building()
	{
		m_sittingRoom = "客厅";
		m_bedRoom = "卧室";
	}

	string m_sittingRoom;

private:
	string m_bedRoom;
};

class GoodGay
{
public:
	GoodGay()
	{
		building = new Building;  //new什么就返回什么,创建了一个Building指针
	}

	Building* building;

	void visit()
	{

		cout << "GoodGay is visting :" << building->m_sittingRoom << endl;

		cout << "GoodGay is visting :" << building->m_bedRoom << endl;
	}
};


int main()
{
	GoodGay gay;
	gay.visit();
	return 0;
}

(2)在类外实现成员函数

class Building
{

	//goodGay函数是 Building的好朋友,可以访问类内的私有成员
	friend class GoodGay;

public:
	Building();
	{
		m_sittingRoom = "客厅";
		m_bedRoom = "卧室";
	}

	string m_sittingRoom;

private:
	string m_bedRoom;
};

class GoodGay
{
public:
	GoodGay();

	void visit();  //用来访问building对象里面的属性

	Building* building;
};

//类外实现成员函数
Building::Building()
{
	m_sittingRoom = "客厅";
	m_bedRoom = "卧室";
}

GoodGay::GoodGay()
{
	building = new Building;  //new什么就返回什么,创建了一个Building指针
}

void GoodGay::visit()
{

	cout << "GoodGay is visting :" << building->m_sittingRoom << endl;

	cout << "GoodGay is visting :" << building->m_bedRoom << endl;
}

int main()
{
	GoodGay gay;
	gay.visit();
	return 0;
}

3 全局函数做友元

四 运算符重载

作用:实现自定义变量的运算符重载
在这里插入图片描述

1.加号运算符重载(成员函数实现和全局函数实现)

(1).成员函数实现

class Person
{
public:
	Person operator+(Person &p)
	{
		Person temp;
		temp.m_a = this->m_a + p.m_a;
		temp.m_b = this->m_b + p.m_b;
		return temp;
	}

	int m_a;
	int m_b;
};


void test()
{
	Person p1;
	p1.m_a = 10;
	p1.m_b = 20;

	Person p2;
	p2.m_a = 10;
	p2.m_b = 20;
	
	// 下面语句等价于 Person p3 = p1 + p2;
	Person p3 = p1.operator+(p2);

	cout << " p3.m_a = " << p3.m_a << endl;
	cout << " p3.m_b = " << p3.m_b << endl;
}


int main()
{
	test();
	return 0;
}

(2).全局函数重载

class Person
{
public:

	int m_a;
	int m_b;
};

Person operator+(Person& p1, Person& p2)
{
	Person temp;
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}

void test()
{
	Person p1;
	p1.m_a = 10;
	p1.m_b = 20;

	Person p2;
	p2.m_a = 10;
	p2.m_b = 20;
	
	//下面语句等价于 Person p3 =operator+(p1,p2);
	Person p3 = p1 + p2;

	cout << " p3.m_a = " << p3.m_a << endl;
	cout << " p3.m_b = " << p3.m_b << endl;
}


int main()
{
	test();
	return 0;
}

(3).运算符重载也可以实现函数重载

class Person
{
public:

	int m_a;
	int m_b;
};

Person operator+(Person& p1, Person& p2)
{
	Person temp;
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}

//运算符重载也可以实现函数重载
Person operator+(Person& p1, int num)
{
	Person temp;
	temp.m_a = p1.m_a + num;
	temp.m_b = p1.m_b + num;
	return temp;
}

void test()
{
	Person p1;
	p1.m_a = 10;
	p1.m_b = 20;

	Person p2;
	p2.m_a = 10;
	p2.m_b = 20;
	
	Person p3 = p1 + p2;
	cout << " p3.m_a = " << p3.m_a << endl;
	cout << " p3.m_b = " << p3.m_b << endl;

	Person p4 = p1 + 100;
	cout << " p4.m_a = " << p4.m_a << endl;
	cout << " p4.m_b = " << p4.m_b << endl;
}


int main()
{
	test();
	return 0;
}

2. 左移运算符重载 <<

//左移运算符( << )重载
//重载左移运算符 ,实现语句 cout << p 打印类里面的相关内容;

class Person
{
	friend ostream& operator<<(ostream& cout, Person& p);

public:
	Person(int a, int b)
	{
		m_a = a;
		m_b = b;
	}
private:
	//不能用成员函数实现左移运算符  目标实现:cout << p 
	//void operator<<(cout)  ,调用时候,调用语句是p.operator<<(cout)  调用时,可以简化为调用语句  p << cout,是反的
	//{
	//}

	int m_a;
	int m_b;
};

ostream& operator<<(ostream &cout , Person &p) //调用语句 operator<<( cout , p) == cout << p ,和前面的加号运算符重载可以简化为 p1+p2是一样的
{
	cout << " p.m_a = " << p.m_a << endl;
	cout << " p.m_b = " << p.m_b << endl;
	return cout;
}

void test()
{
	Person p(10,10);
	cout << p << "hello " << endl;
}

int main()
{
	test();
	return 0;
}

举报

相关推荐

2022/4/1

【2022/4/29】CCF202203-1

2022/4/4

2022/4/9-2022/4/10

2022/4/4偷懒

0 条评论