2021-11-07 C++封装继承多态---类和对象基本概念关系、对象的初始化和清理(附代码理解)

1 类和对象的概念和关系

类是对现实生活中一类具有共同属性和行为的事物的抽象
类的特点:1.类是对象的数据类型 2.类是具有相同属性和行为的一组对象的集合
什么是对象的属性? 属性: 对象具有的各种特征,每个对象的每个属性都拥有特定的值
什么是对象的行为? 行为:对象能够执行的操作
类和对象的关系 :
类:类是对现实生活中一类具有共同属性和行为的事物的抽象 对象:是能够看得到摸得着的真实存在的实

1.1 访问权限

类在设计时,可以把属性和行为放在不同的权限下,加以控制访问权限有三种:
1.public公共权限 2. protected保护权限 3. private私有权限

#include<iostream>
using namespace std;

class Person
{
public:
	string m_name;
protected:
	string m_car;
private:
	int m_password;
public:
	void func()
	{
		m_name = "sss";
		m_car = "aaaaaaaaaaaaaa";
		m_password = 1111111111111;
	}
};

int main() {
	Person p1;

	p1.m_name = "aaaaaaaasssssssss";
	//p1.m_car = "sadsfsfsafa";
	void func();
	cout<<p1.m_name<<endl;  //公有权限,所以可以改变
	system("pause");
	return 0;
}

在这里插入图片描述

1.2 struct和class的区别

在C++中struct和class唯一的区别就在于默认的访问权限不同区别:
struct 默认权限为公共 class默认权限为私有

#include<iostream>
using namespace std;

class C1
{
	int m_a; //私有
};
struct C2
{
	int m_a; //公共
};
int main() {
	C1 c1; //实例化对象
	c1.m_a = 100; //不可以访问

	C2 c2;
	c2.m_a = 100;  //可以访问
	system("pause");
	return 0;
}

1.3 成员属性私有化

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

#include<iostream>
using namespace std;

class Person
{
public:
	//提供一点公共的接口让你操作吧
	//以函数的形式实现可读可写
	//设置姓名
public:
	void setname(string name)
	{
		m_name = name;
	}
	//获取姓名
	string getname()
	{
		return m_name;
	}
	//年龄是只读的
	int getage()
	{
		int m_age = 999;
		return m_age;
	}
	//只写权限   //这个函数接口没有读出的语句
	void setlover(string lover)  
	{
		m_lover = lover;
	}
private:
	//name  可读可写
	string m_name;
	//age   只读
	string m_age;
	//情人  只写
	string m_lover;
};

int main() {
	Person p1;
	p1.setname("张三");
	cout << "姓名为" << p1.getname() << endl;
	cout << "年龄为" << p1.getage() << endl;
	//设置情人
	p1.setlover("仓井");
	//cout <<"情人为" << p1.m_lover<<endl; //不可访问咯!!!
	system("pause");
	return 0;
}

1.4 案例-设计立方体类

在这里插入图片描述

#include<iostream>
using namespace std;
//1 创建立方体类
//2 设计属性
//3 设计行为,获取面积,体积
//4 分别利用全局函数和成员函数,判断立方体是否相等

class Cube
{
public:
	//设置长
	void setl(int l )
	{
		m_l = l;
	}
	//获取长
	int getl()
	{
		return m_l;
	}
	//设置宽
	void setw(int w)
	{
		m_w = w;
	}
	//获取宽
	int getw()
	{
		return m_w;
	}
	//设置高
	void seth(int h)
	{
		m_h = h;
	}
	//获取高
	int geth()
	{
		return m_h;
	}
	//获取立方体面积
	int calculaetS()
	{
		return 2 * m_l * m_w + 2 * m_w * m_h + 2 * m_l * m_h;
	}
	//获取立方体体积
	int calculateV()
	{
		return m_l * m_w * m_h;
	}
//成员函数判断两个立方体是否相等
	bool issamebyclass(Cube &c2)
	{
		if (m_l == c2.getl() && m_w == c2.getw() && m_h == c2.geth())//自身的长宽高和传进来的长宽高进行对比判断
		{
			return true;
		}
		return  false;
	}
private:
	int m_l;
	int m_w;
	int m_h;

};

//利用全局函数判断两个立方体是否相同
bool issame(Cube c1, Cube c2)
{
	if (c1.getl() == c2.getl() && c1.getw() == c2.getw() && c1.geth() == c2.geth())
	{
		return true;
	}
	return false;
}


int main() {
	
	//实例化对象
	Cube c1;
	
	c1.seth(10);
	c1.setl(10);
	c1.setw(10);

	cout << "体积为" << c1.calculaetS() << endl;
	cout << "面积为" << c1.calculateV() << endl;

	//创建第二个立方体
	Cube c2;
	c2.seth(10);
	c2.setl(10);
	c2.setw(10);
	//全局函数,开始判断
	bool ret = issame(c1, c2);
	if (ret)
	{
		cout<<"全局函数,开始判断,体积是相等的" << endl;
	}
	else
	{
		cout << "体积不是相等的" << endl;

	}
	//成员函数开始判断
	ret = c1.issamebyclass(c2);
	if (ret)
	{
		cout << "成员函数开始判断,体积是相等的" << endl;
	}
	else
	{
		cout << "体积不是相等的" << endl;

	}

	system("pause");
	return 0;
}

1.5 案例-点和圆的关系

在这里插入图片描述

#include<iostream>
using namespace std;
//点类
class point
{
public:
	//设置x
	void setx(int x)
	{
		m_x = x;
	}
	//获取x
	int getx()
	{
		return m_x;
	}
	//设置y
	void sety(int y)
	{
		m_y = y;
	}
	//获取y
	int gety()
	{
		return m_y;
	}
private:
	int m_x;
	int m_y;

};
//圆类
class circle
{
public:
	//设置半径
	void setr(int r)
	{
		m_r = r;
	}
	//获取半径
	int getr()
	{
		return m_r;
	}
	//设置圆心
	void setcenter(point center)
	{
		m_center = center;
	}
	//获取圆心
	point getcenter()
	{
		return m_center;
	}

private:
	int m_r;
	point m_center;


};
//判断点和圆的关系
void isincircle(circle& c, point& p)
{
	//计算两点之间的距离  平方
	int distance =
		(c.getcenter().getx() - p.getx()) * (c.getcenter().getx() - p.getx()) +
		(c.getcenter().gety() - p.gety()) * (c.getcenter().gety() - p.gety());
	//计算半径的平方
	int rdistance =
		c.getr() * c.getr();
	//判断关系
	if (distance = rdistance)
	{
		cout<<"点在圆上" << endl;

	}
	else if (distance > rdistance) 
	{
		cout << "点在圆外" << endl;
	}
	else
	{
		cout << "点在圆内" << endl;

	}
}

int main2() {

	//创建圆
	circle c;
	c.setr(10);
	point center;
	center.setx(10);
	center.sety(0);
	c.setcenter(center);

	//创建点
	point p;
	p.setx(10);
	p.sety(10);

	//判断关系
	isincircle(c, p);

	system("pause");
	return 0;
}

2 对象的初始化和清理

生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候也会删除一些自己信息数据保证安全。
C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置。

2.1 构造函数和析构函数

对象的初始化和清理也是两个非常重要的安全问题,一个对象或者变量没有初始状态,对其使用后果是未知,同样的使用完一个对象或变量,没有及时清理,也会造成—定的安全问题。
C++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供编译器提供的构造函数和析构函数是空实现

构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。·
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作

构造函数语法:析构函数语法:
1.构造函数,没有返回值也不写void1.析构函数,没有返回值也不写void
2.函数名称与类名相同⒉.函数名称与类名相同,在名称前加上符号~
3.构造函数可以有参数,因此可以发生重载3.析构函数不可以有参数,因此不可以发生重载
4.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次4.程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
#include<iostream>
using namespace std;
//构造函数  初始化
//析构函数 清理
class person
{
public:
	//构造函数
	person()
	{
		cout << "构造函数" << endl;
	}
	
	//析构函数
	~person()
	{
		cout<<"析构函数" << endl;
	}
};
void test01()
{
	cout <<"aaaa" << endl;
	person p; //站上的数据,执行完毕后,就会释放这个对象
}

int main4() {
	test01();

	system("pause");
	return 0;
}

2.2 构造函数的分类以及调用

两种分类方式:
按参数分为:有参构造和无参构造
按类型分为:普通构造和拷贝构造
三种调用方式:括号法显示法隐式转换法

#include<iostream>
using namespace std;
//分类

class person
{
public:
	//普通函数
	//构造函数
	person()
	{
		cout << "构造函数" << endl;
	}
	//有参构造函数
	person(int a )
	{
		age = a;
		cout << "youcan构造函数" << endl;
	}
	//拷贝构造函数
	person(const person &p)
	{
		age = p.age;
		cout << "拷贝构造函数" << endl;
		//将传入的人的所有属性,拷贝到他身上
	}

	//析构函数
	~person()
	{
		cout << "析构函数" << endl;
	}
	int age;
};
//调用
void test01()
{
	//1 括号法
	//person p1;//默认构造
	//person p2(10);//有参构造
	//person p3(p2);//拷贝构造
	//cout << "p2年龄" << p2.age<<endl;
	//cout << "p3年龄" <<p3.age <<endl;

	//注意 1 :
	//调用默认构造函数,不要加(),因为编译器会认为这是一个函数的声明
	//person p1();
	
	//2 显示法
	person p1;//默认构造
	person p2 = person(10);//有参构造
	person p3 = person(p2);//拷贝构造

	//person(10)  匿名对象。 特点:当前行执行结束后,系统就会回收了;
	//注意 2 :
	//不要利用拷贝构造, 初始化匿名对象 , 编译器会认为 person(p3) == person p3; 对象声明
	//person (p3);
	
	//3 隐式转换法
	person p4 = 10; //有参构造
	person p5 = p4;//拷贝构造
}
int main() {
	test01();
	system("pause");
	return 0;
}

2.3 拷贝构造函数调用时机

C++中拷贝构造函数调用时机通常有三种情况
1.使用一个已经创建完毕的对象来初始化一个新对象·
2.值传递的方式给函数参数传值
3.以值方式返回局部对象

#include<iostream>
using namespace std;
//拷贝构造函数调用时机
//1 使用一个已经创建完毕的对象来初始化一个新对象
//2 值传递的方式给函数参数传值
//3 值方式返回局部对象
class person
{
public:
	//构造函数
	person()
	{
		cout << "默认构造函数" << endl;
	}
	person(int age)
	{
		m_age = age;
		cout << "有参构造函数" << endl;
	}
	//拷贝构造函数
	person(const person& p)
	{
		m_age = p.m_age;
		cout << "拷贝构造函数" << endl;

		//将传入的人的所有属性,拷贝到他身上
	}

	//析构函数
	~person()
	{
		cout << "析构函数" << endl;
	}
	int m_age;
};
//1 使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{
	person p1(20);
	person p2(p1);
	cout << "p2的年龄" << p2.m_age<<endl;
}
//2 值传递的方式给函数参数传值
void dowork(person p)
{

}
void test02()
{
	person p;
	dowork(p);

}
//3 值方式返回局部对象  //拷贝只传值,不传地址,所以值一样,地址不一样
person dowork2( )
{
	person p1;
	cout<<(int*)&p1<<endl;
	return p1;
}
void test03()
{
	person p = dowork2();
	cout << (int*)&p << endl;
}

int main() {

	//test01();
	test03();
	system("pause");
	return 0;
}

2.4 构造函数调用规则

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

#include<iostream>
using namespace std;
//1 创建一个类,c++会给每个类至少添加三个函数
class person
{
public:
	//person()
	//{
	//	cout << "构造函数" << endl;
	//}
	//有参构造函数
	person(int a)
	{
		age = a;
		cout << "有参构造函数" << endl;
	}
	//拷贝构造函数
	//person(const person& p)
	//{
		//age = p.age;
		//cout << "拷贝构造函数" << endl;

		//将传入的人的所有属性,拷贝到他身上
	//}

	//析构函数
	~person()
	{
		cout << "析构函数" << endl;
	}
	int age;
};
//1 创建一个类,c++会给每个类至少添加三个函数
//void test01()
//{
//	person p;
//	p.age = 18;
//	person  p2(p);
//	cout << "p2年龄为" << p2.age<<endl;
//}

//2 如果写了有参构造函数,编译器就不再提供默认构造,依然提供拷贝构造★★★★★★★★★★★★★★★★★★★★★★★
// 如果写了拷贝构造函数,编译器就不提供其他的了。★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
void test02()
{
	person p(129);
	person  p2(p);
	cout << "p2年龄为" << p2.age << endl;
}
int main() {
	//test01();
	test02();

	system("pause");
	return 0;
}

2.5 浅拷贝和深拷贝

浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作

#include<iostream>
using namespace std;
class person
{
public:
	//构造函数
	person()
	{
		cout << "构造函数" << endl;
	}
	//有参构造函数
	person(int a, int height)
	{
		m_age = a;
		m_height = new int(height);
		cout << "youcan构造函数" << endl;
	}
	//之前没有写拷贝构造函数,就是系统默认的垃圾拷贝构造函数啊。
	//自己实现拷贝构造函数,解决浅拷贝带来的问题
	person(const person& p)
	{
		cout<<"拷贝构造函数调用,myself" << endl;
		m_age = p.m_age;
		//m_height = p.m_height;  编译器默认实现的就是这行代码  qiankaobei
		//深拷贝操作
		m_height = new int(*p.m_height);  //从新申请一块内存    shenkaobei
	}
	//析构函数
	~person()
	{
		//析构代码, 将堆区开辟的数据做释放操作
		if (m_height != NULL)
		{
			delete m_height;
			m_height = NULL;
		}
		cout << "析构函数" << endl;
	}
	int m_age;
	int* m_height;
};
void test01()
{
	person p1(18, 160);

	cout << "p1的年龄为" <<p1.m_age<< "身高为" <<*p1.m_height<< endl;
	person p2(p1);   //浅拷贝??
	cout << "p2的年龄为" << p2.m_age <<"身高为" << *p2.m_height<< endl;
}

int main() {
	test01();
	
	system("pause");
	return 0;
}

2.6 初始化列表

作用:C++提供了初始化列表语法,用来初始化属性
语法:构造函数()∶属性1(值1) ,属性2(值2) …

#include<iostream>
using namespace std;
class person
{
public:
	//传统初始化的操作
	//person(int a, int b, int c)
	//{
	//	m_a = a;
	//	m_b = b;
	//	m_c = c;
	//}
	//初始化列表初始化属性
	person() : m_aa(10), m_bb(20), m_cc(30)
	{

	}
	//初始化列表初始化属性,升华
	person(int aa, int bb, int cc) : m_aaa(aa), m_bbb(bb), m_ccc(cc)
	{

	}
	int m_a;
	int m_b;
	int m_c;
	int m_aa;
	int m_bb;
	int m_cc;
	int m_aaa;
	int m_bbb;
	int m_ccc;
};
   

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_aa" << p.m_aa << endl;
	cout << "m_bb" << p.m_bb << endl;
	cout << "m_cc" << p.m_cc << endl;
}
void test03()
{
	person p(99,88,55);
	cout << "m_aa" << p.m_aaa << endl;
	cout << "m_bb" << p.m_bbb << endl;
	cout << "m_cc" << p.m_ccc << endl;
}
int main() {
	test03();

	system("pause");
	return 0;
}

2.7 类对象作为类成员

C++类中的成员可以是另一个类的对象,我们称该成员为对象成员。
B类中有对象A作为成员,A为对象成员。
那么当创建B对象时,A与B的构造和析构的顺序是谁先谁后?

#include<iostream>
using namespace std;
//手机类
class phone
{
public:
	phone(string pname)
	{
		cout << "phone 的构造函数的调用" << endl;
		m_pname = pname;
	}
	//析构函数
	~phone()
	{
		cout << "phone析构函数" << endl;
	}
	//手机品牌名称 
	string m_pname;
};
//人类
class person
{
public:
	// phone m_phone = pname  隐式转换法
	person(string name, string pname) :m_name(name), m_phone(pname)
	{
		cout <<"person 的构造函数的调用" << endl;
	}
	//析构函数
	~person()
	{
		cout << "person析构函数" << endl;
	}
	//xingming
	string m_name;
	//phone
	phone m_phone;
};

// 当其他的类对象作为本类的成员时候,构造时候先构造类对象,再构造自身,而析构呢???????

void test01()
{
	person p("张三", "苹果max");
	cout << p.m_name << "拿着" << p.m_phone.m_pname << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

在这里插入图片描述

2.8 静态成员

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:

静态成员变量静态成员函数
所有对象共享同一份数据。在编译阶段分配内存所有对象共享同一个函数
类内声明,类外初始化·静态成员函数只能访问静态成员变量

2.8.1静态成员变量(1)

#include<iostream>
using namespace std;
//静态成员变量
class person
{
public:
	//1 所有对象都共享同一份数据
	static int m_a;
private:
	static int m_b;

};
int person::m_a = 100;
int person::m_b = 200;
void test01()
{
	person p;
	cout<<p.m_a<<endl;

	person p2;
	p2.m_a = 200;
	cout << p2.m_a << endl;
	cout << p.m_a << endl;
}
void test02()
{
	//静态成员变量 不属于某个对象 所有对象都共享同一份数据

	//1.通过对象访问
	person p;
	cout <<p.m_a<<endl;
	//2. 通过类名访问
	cout << person::m_a << endl;
	cout << person::m_a << endl;

}
int main() {
	test01();
	system("pause");
	return 0;
}

2.8.2 静态成员变量(2)

#include<iostream>
using namespace std;
//静态成员函数
class person
{
public:
	//1 所有对象都共享同一份数据
	static void func()
	{
		m_a = 100;  //静态成员可以访问 静态成员变量
		//m_b = 200;  //静态成员函数 不可以访问 非静态成员变量,无法区别到底是那个对象的m_b

		cout << "static的调用" << endl;
	}
	static int m_a;
	int m_b ;
private:
	static void func2()
	{
		cout << "私有的static的调用" << endl;
	}

};
int person::m_a = 100;

void test01()
{

	//1.通过对象访问
	person p;
	p.func();
	//2. 通过类名访问
	person::func();
	//person::func2();  //私有不可以访问 !!!!!!!!
}
int main() {
	test01();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值