c++(六)


在这里插入图片描述

多态

概念

多种状态(一个事物的多种状态或形态)

<1>水在不同的温度下呈现的不同状态
<2>买票
学生票;
成人票;
老年票;
军人;

在c++中是如何实现多态

绑定:就是把函数调用语句与对应的代码块进行了绑定!。

静态多态(绑定)

编译的时候,就知道执行的是哪一个函数体
调用函数时,函数名是一样的,当我们传入不同参数的时候,执行的是不同的函数体(函数重载、运算符重载)

动态多态(绑定)

在运行的时候,才知道执行的是哪一个函数体

案例:如果要求两个子类的周长和面积之和,就得写两个函数来实现,传入不同的对象
在这里插入图片描述

在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	~Shape()
	{
		cout << "Shape析构" << endl;
	}
	int getC()
	{
		cout << "周长:" << this->c << endl;
		return this->c;
	}
	int getS()
	{
		cout << "面积:" << this->s << endl;
		return this->s;
	}
private:
protected:
	int s;
	int c;
};
class Rect:public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle:public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Rcs(Rect & demo)
{
	cout << demo.getC()+ demo.getS()<< endl;
}
void Ccs(Circle& demo)
{
	cout << demo.getC() + demo.getS() << endl;
}
int main()
{
	//矩形对象
	Rect rect(2,3);
	Rcs(rect);
	
	//圆形对象
	Circle circle(3);
	Ccs(circle);


}

解决:用父类统一管理子类
在这里插入图片描述
问题:通过父类的引用操作子类的对象时,并没有执行子类的函数,执行的是子类从父类继承过来的函数
在这里插入图片描述
解决:目的:执行子类重定义的函数,将父类对应的函数写成虚函数
虚函数的格式:

virtual 返回值类型 函数名(参数列表){}

未加victual之前,不能访问子类重定义函数的原因:
将子类对象强制赋值给父类的引用,父类的引用所访问的范围小,访问不到子类的函数
在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	~Shape()
	{
		cout << "Shape析构" << endl;
	}
	virtual int getC()
	{
		cout << "周长:" << this->c << endl;
		return this->c;
	}
	virtual int getS()
	{
		cout << "面积:" << this->s << endl;
		return this->s;
	}
private:
protected:
	int s;
	int c;
};
class Rect:public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle:public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Scs(Shape & demo)
{
	cout << demo.getC()+ demo.getS()<< endl;
}
int main()
{
	//矩形对象
	Rect rect(2,3);
	Scs(rect);
	
	//圆形对象
	Circle circle(3);
	Scs(circle);


}

在这里插入图片描述

动态多态的实现原理

有虚函数一定能实现动态多态吗?不一定

多态的实现:
<1>一个父类,有多个子类
<2>父类中有虚函数,子类重写父类的虚函数
<3>用父类对象的指针或者引用去操作子类的对象并调用虚函数的受,才会触发动态多态(决定性因素)

将父类的对应的函数写成虚函数,在子类中进行重写,通过父类对象的指针/引用去操作子类对象就可以调用到子类的函数了

指针所能访问的空间的大小:由指针指向的数据类型大小决定

int *p; //4字节
shape *p;// 8个字节

在这里插入图片描述
为什么添加virtual就可以访问子类的函数?

虚函数表:保存虚函数的地址(函数指针数组)

什么时候有虚函数表?

一个类中一旦有了虚函数,那么这个类中就有了一个虚函数表,保存这个类中所有虚函数的地址,如果这个类被子类继承了,子类中也会有一张虚函数表

父类的虚函数表和子类的虚函数表一样吗?

<1>如果子类不重写父类的虚函数,那么父类和子类的虚函数表是一样的
<2>如果子类重写了父类的虚函数,那么子类虚函数表中对应的就是子类重写之后的虚函数地址

在这里插入图片描述

  1. 父类有虚函数,那么被子类继承之后,子类中对应的函数也是虚函数!子类中对应函数的virtual关键字可加可不加!
  2. 父类中有函数是虚函数,如果子类有重定义的话,此时被称为重写(覆盖–就是子类中的函数把从父类中继承来的给覆盖了。子类中有且只有一个这样子的函数!!!)!!!!
  3. 重写就必须保证 子类中的函数首部与父类中函数的首部是一模一样的,首部指的是:函数类型 函数名(参数列表)。

动态内存分配中遇到的问题

问题:把new出来的子类对象,赋值给了父对象类型的指针,在整个操作过程中,都是通过父类的指针来操作,使用delete去释放空间的时候,只执行了父类的析构函数,并没有子类的析构函数,可能会造成内存泄漏的问题(在子类的构造函数去new空间了)
在这里插入图片描述

在这里插入图片描述

解决:目标:执行子类的析构函数
将父类的析构函数写成虚函数,子类的析构自然也是虚函数!

在这里插入图片描述

#include <iostream>
using namespace std;
class Shape
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	virtual ~Shape()
	{
		cout << "Shape析构" << endl;
	}
	virtual int getC()
	{
		cout << "周长:" << this->c << endl;
		return this->c;
	}
	virtual int getS()
	{
		cout << "面积:" << this->s << endl;
		return this->s;
	}
private:
protected:
	int s;
	int c;
};
class Rect :public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle :public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Scs(Shape* demo)
{
	cout << demo->getC() + demo->getS() << endl;
}
int main()
{

	Shape* p = new Circle(4);
	Scs(p);
	delete p;


}

<1>在设计类的时候,为什么建议把析构函数写成虚函数
防止内存泄漏
<2>为什么不执行子类的析构函数就可能会存在内存泄漏的问题
在子类的构造函数去new空间了

重载、重定义、重写的区别

重载:同一个作用域内,函数功能相似,函数名相同、参数不同,与返回值无关的一组函数
重定义:在继承关系中,子类重定义父类的函数,函数名相同即可
重写(覆盖):在继承关系中,子类重写父类的虚函数
备注:函数首部必须一样
首部:返回值类型 函数名(形式参数列表)

抽象类

在设计类的时候,发现这个类确实需要这样子的一个操作函数,但是在父类中不知道该怎么实现,它的所有的子类都要实现这个函数,并且所有的子类实现这个函数的效果是不一样的,这种情况下,就可以把这个函数写成纯虚函数

virtual 返回值类型 函数名(形参列表) = 0;

在这里插入图片描述
注意:抽象类是不能创建对象的
在这里插入图片描述

作用:就是用来被继承的,在子类中去实现这个纯虚函数(每一个子类都要去实现这个纯虚函数)
如果子类没有实现这个纯虚函数,子类也变成了抽象类

#include <iostream>
using namespace std;
class Shape //抽象类
{
public:
	Shape(int s = 0, int c = 0) :s(s), c(c)
	{
		cout << "Shape构造" << endl;
	}
	virtual ~Shape()
	{
		cout << "Shape析构" << endl;
	}
	virtual int getC() = 0;//纯虚函数
	
	virtual int getS() = 0;
	
private:
protected:
	int s;
	int c;
};
class Rect :public Shape
{
public:
	Rect(int a = 0, int b = 0) :a(a), b(b)
	{
		cout << "Rect构造" << endl;
	}
	~Rect()
	{
		cout << "Rect析构" << endl;
	}
	int getC()
	{
		this->c = (this->a + this->b) * 2;
		return this->c;
	}
	int getS()
	{
		this->s = this->a * this->b;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int a;
	int b;
};
class Circle :public Shape
{
public:
	Circle(int r = 0) :r(r)
	{
		cout << "Circle构造" << endl;
	}
	~Circle()
	{
		cout << "Circle析构" << endl;
	}
	int getC()
	{
		this->c = 2 * 3.14 * this->r;
		return this->c;
	}
	int getS()
	{
		this->s = 3.14 * this->r * this->r;
		return this->s;
	}
	void show()
	{
		cout << "周长:" << this->c << ",面积:" << this->s << endl;
	}
private:
protected:
	int r;
};
void Scs(Shape* demo)
{
	cout << demo->getC() + demo->getS() << endl;
}
int main()
{

	Shape* p = new Circle(4);
	Scs(p);
	delete p;


}

在这里插入图片描述

接口类—抽象类

接口类其实就是抽象类的应用
当抽象类不能实例化对象时,抽象类中的成员变量也就不能初始化,其构造函数也就不能被执行

接口类:类中只有成员函数,没有数据成员,并且成员函数必须是纯虚函数
作用:就是用来被继承的,描述一些能力、协议

#include <iostream>
using namespace std;
//接口类
class fly_land
{
public:
	virtual void fly() = 0;//纯虚函数
	virtual void land() = 0;
};
class Bird :public fly_land
{
public:
	void fly()
	{
		cout << "bird  fly ....." << endl;
	}
	void land()
	{
		cout << "bird land....." << endl;
	}
};
class Plane :public fly_land
{
public:
	void fly()
	{
		cout << "plane fly....." << endl;
	}
	void land()
	{
		cout << "plane land....." << endl;
	}
};
void dosomething(fly_land& demo)
{
	demo.fly();
}
int main()
{
	Bird bird;
	dosomething(bird);

	Plane plane;
	dosomething(plane);
}

在这里插入图片描述

空类对象的内存大小

默认构造函数、析构函数、默认拷贝构造函数、赋值运算符函数、取值运算符函数 const 修饰的取值运算符
空类占内存大小:1字节
在这里插入图片描述
在这里插入图片描述

explicit

作用:修饰构造函数的,对应的构造函数被称为 转换构造函数!!!!
意义:防止构造函数单参数的时候进行自动类型的转换

在这里插入图片描述

final

作用:修饰类和类中的成员函数

修饰类

作用:不能被继承
在这里插入图片描述

修饰成员函数

作用:无法重写
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值