C++虚函数和多态09 提高代码复用率

C++虚函数和多态

虚函数和虚函数表

普通函数不影响类大小
虚函数表:因为此指针指向所有虚函数首地址存储内存段,所以叫表

  • 什么是虚函数? 用virtual 修饰的成员函数叫做虚函数
  • 虚函数对于类的影响
    • 增加一个指针的内存,32位4个字节 ,64位就是8个字节
  • 虚函数表(了解一下): 就是一个指针存储所有虚函数的首地址
    +在这里插入图片描述
#include <iostream>
using namespace std;
class GG
{
public:
	virtual void print1()
	{
		cout << "虚函数1" << endl;
	}
	virtual void print2()
	{
		cout << "虚函数2" << endl;
	}
	virtual void print3();

protected:
};
void GG::print3()  
{
	cout << "虚函数3" << endl;
}

class TEST
{
	int age;
};
void testVirtual()
{
	//C语言不允许存在空的结构体
	cout << sizeof(GG) << endl;		//空的类或者而结构体 占用1字节
	cout << sizeof(TEST) << endl;
	GG gg;
	//By虚函数表  调用虚函数
	// 不必要这样自己增加难度
	int** vptr = (int**)&gg;
	typedef void(*PF)();
	PF func = (PF)vptr[0][0];
	func();		//调用第一个虚函数
	func = (PF)vptr[0][1];
	func();		//调用第二个虚函数
}
int main()
{
	testVirtual();
	return 0;
}

在这里插入图片描述

虚函数和多态

  • 多态定义: 同一种行为(调用)导致的不同的结果
    因为对象不同而结果不同
    撞:男人 上厕所和女人上厕所 行为因对象而不同
  • 多态的必要性原则
    • 必须父类存在虚函数
    • 子类必须采用public继承
    • 必须存在指针的引用(使用)
#include <iostream>
using namespace std;
class Man
{
public:
	void WC1()
	{
		cout << "普通函数:男人上厕所" << endl;
	}
	virtual void WC2()   //父类必须要有virtual
	{
		cout << "虚函数:龌龊男人上厕所" << endl;
	}
protected:
};
class Woman :public Man
{
public:
	void WC1()  // 普通函数
	{
		cout << "普通函数:女人上厕所" << endl;
	}
	void WC2()// 普通函数
	{
		cout << "普通函数:女人上厕所" << endl;
	}
protected:

};
void testVirtual()
{
	//正常访问不存在多态
	cout << "正常访问,就近原则" << endl;
	Man  man;
	man.WC1();
	man.WC2();

	cout << "指针非正常赋值:子类对象初始化父类指针" << endl;
	Man* parent = new Woman;
	//有virtual看对象类型,没有virutal看指针
	parent->WC1();			//不是虚函数
	parent->WC2();			//是虚函数
	parent = new Man;       //fangwen man
	parent->WC2(); 
}
int main()
{
	testVirtual();
	return 0;
}

在这里插入图片描述

好处和应用:可以统一接口;行为统一
例如:统一接口功能

void printInfo(Man* parent) 
{
	parent->WC2();
}

纯虚函数和ADT

纯虚函数就是做ADT(abstract data type 抽象数据类型)过程
  • 纯虚函数也是虚函数只是纯虚函数是没有函数体的

    virutal void print()=0;     //在类中函数 这样写法
    
  • 抽象类: 具有至少一个纯虚函数的类,叫做抽象类

    • 抽象类不能构建对象
    • 抽象类可以构建对象指针
  • 纯虚函数没有被重写,无论被继承多少次 都是纯虚函数,虚函数无论被继承多少次都是虚函数

#include <iostream>
using namespace std;
//抽象类
class Parent
{
public:
	virtual void print() = 0;		//纯虚函数
protected:
};
void testAbstract()
{
	//Parent object;  不能构建对象
	cout << "testAbstract()" << endl;
	Parent* parent = nullptr;
}

//纯虚函数就是做ADT(abstract data type 抽象数据类型)过程
//子类想要创建对象,必须重写父类的纯虚函数
//ADT: 具有强迫性,所有子类重写函数必须和父类的一模一样
//纯虚函数没有被重写,无论被继承多少次 都是纯虚函数,
//虚函数无论被继承多少次都是虚函数
class A
{
public:
	virtual void print() = 0;
protected:
};
class B :public A
{
public:
	void print()
	{
		cout << "B" << endl;
	}
};
class C :public B
{
public:
	void print()
	{
		cout << "C" << endl;
	}
};
void Abtract()
{
	//B b;
	C c;  //一般抽象类只被继承一次就重写
	B* pc = new C;
	pc->print();
}
int main()
{
	Abtract();
	return 0;
}
  • 一般抽象类只被继承一次就重写
  • 不重写实现它 他的继承只能是纯虚函
父类B中重写了,在这里C中实现了?

在这里插入图片描述

  • 子类想要创建对象,必须重写父类的纯虚函数
  • ADT: 具有强迫性,所有子类重写函数必须和父类的一模一样
  • <<<<< 栈我会在找机会补上
虚析构函数

原因:不正常赋值 导致了释放问题—》

#include <iostream>
using namespace std;
class parent
{
public:
	//虚析构函数,不存在虚构造函数
	virtual ~parent()
	{
		cout << "父类析构" << endl;
	}
	void print() {
		name = "ALBANIYA";
		cout << name << endl;
	}
protected:
	string name = new char[10];

};
class son :public parent
{
public:
	void print()
	{
		cout << name << endl;
	}
	~son()
	{
		cout << "子类析构" << endl;
	}
	string name = "baby";
};
int main()
{
	//在用子类对象初始化父类指针,父类需要虚析构函数做内存释放
	//virtual ~parent() 没有virtual就子类不释放
	parent* p = new son;
	p->print();
	son s;
	//s.print(); //正常赋值调用
	delete p;
	s.print(); //正常赋值调用
	return 0;
}

在这里插入图片描述

总结:
cout << “指针非正常赋值:子类对象初始化父类指针” << endl;
Man* parent = new Woman;
//有virtual看对象类型,没有virutal看指针
parent->WC1(); //不是虚函数
parent->WC2(); //是虚函数

  • 在用子类对象初始化父类指针,父类需要虚析构函数做内存释放
  • virtual ~parent() 没有virtual就子类不释放

最后析构是释放内存;而子类对象在父类基础上创建,因此 子类对象释放完了才能释放父类对象。

******************口诀
构造:盖房从地基开始盖
析构:拆房从楼顶开始拆
在这里插入图片描述
说你海王人自己可定也是钓鱼的人

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值