C++虚函数和多态

本文介绍了C++中的虚函数和多态概念,包括虚函数的作用、虚函数表、多态的实现条件、纯虚函数与抽象类、虚析构函数的应用,以及C++的类型转换如const_cast、static_cast、dynamic_cast和reinterpret_cast的使用。
摘要由CSDN通过智能技术生成

C++虚函数和多态


一、虚函数和虚函数表

  • 什么是虚函数
    • 用virtual修饰的成员函数叫做虚函数
  • 虚函数对于类的影响
    • 增加一个指针的内存,32位4个字节,64为就是8个字节
  • 虚函数表(了解一下):就是一个指针存储所有虚函数的首地址
#include <iostream>
#include <string>
using namespace std;

class STU
{
public:
	virtual void print1()
	{
		cout << "虚函数1" << endl;
	}
	virtual void print2()
	{
		cout << "虚函数2" << endl;
	}
	virtual void print3();
protected:


};
void STU::print3()
{
	cout << "虚函数3" << endl;
}
class A
{
	int age;
};
void testVirtual()
{
	//C语言不允许存在空的结构体
	cout << sizeof(STU) << endl; //空的类或者结构体占用1个字节
	cout << sizeof(A) << endl;
	STU stu;
	//虚函数表
	int** vptr = (int **)&stu;
	typedef void(*PF)();
	PF func = (PF)vptr[0][0];
	func();	//调用第一个虚函数
	func = (PF)vptr[0][1];
	func();	//调用第二个虚函数
	func = (PF)vptr[0][2];
	func();	//调用第三个虚函数
}
int main()
{
	testVirtual();


	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

二、虚函数和多态

  • 多态定义:同一种行为(调用)导致的不同结果
  • 多态的必要性原则
    • 必须父类存在虚函数
    • 子类必须要采用public继承
    • 必须存在指针引用(使用)
#include <iostream>
#include <string>
using namespace std;

class STU
{
public:
	void Work1()
	{
		cout << "学生写作业" << endl;
	}
	virtual void Work2()	//父类必须要有virtual
	{
		cout << "vitual学生改作业" << endl;
	}
protected:
	
};
class TEACH:public STU
{
public:
	void Work1()
	{
		cout << "老师写作业" << endl;
	}
	void Work2()
	{
		cout << "老师改作业" << endl;
	}
protected:

};
void testVirtual()
{
	//正常访问不存在多态
	cout << "正常访问,就近原则" << endl;
	STU ps;
	ps.Work1();
	ps.Work2();
	TEACH pt;
	pt.Work1();
	pt.Work2();
	cout << "指针访问,正常赋值" << endl;
	STU* stu = new STU;
	stu->Work1();
	stu->Work2();
	TEACH* teach = new TEACH;
	teach->Work1();
	teach->Work2();
	cout << "非正常赋值:子类对象初始化父类指针" << endl;
	STU* parent = new TEACH;
	//有virtual看对象类型,没有virtual看指针
	parent->Work1();	//不是虚函数
	parent->Work2();	//是虚函数
	parent = new STU;
	parent->Work2();
}
void printInfo(STU* parent)
{
	parent->Work2();
}

class Shape
{
public:
	virtual void Draw()
	{
		cout << "绘制过程" << endl;
	}
protected:

};
class Rect :public Shape
{
public:
	void Draw()
	{
		cout << "画矩形" << endl;
	}
protected:

};
class Circle :public Shape
{
public:
	void Draw()
	{
		cout << "画圆" << endl;
	}
protected:
};
class Triangle :public Shape
{
public:
	void Draw()
	{
		cout << "画三角形" << endl;
	}
protected:
};
class Ellipse :public Shape
{
public:
	void Draw()
	{
		cout << "画椭圆" << endl;
	}
protected:
};
//降低因为变化而要修改代码
//采用增加代码的方式满足新需求
//统一接口的功能
class Tool
{
public:
	void draw(Shape* parent)
	{
		parent->Draw();
	}
protected:
};
int main()
{
	testVirtual();
	printInfo(new TEACH);
	Tool* pTool = new Tool;
	pTool->draw(new Circle);
	pTool->draw(new Rect);
	pTool->draw(new Triangle);
	pTool->draw(new Ellipse);
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

三、纯虚函数和ADT

  • 纯虚函数也是虚函数只是纯虚函数是没有函数体的

virtual void print()=0; //在类中函数的写法

  • 抽象类:具有一个纯虚函数的类,叫做抽象类
    • 抽象类不能构造对象
    • 抽象类可以构造对象指针
  • 纯虚函数没有被重写,无论被继承多少次都是纯虚函数,虚函数无论被继承多少次都是虚函数
#include <iostream>
using namespace std;
//抽象类
class Parent
{
public:
	virtual void print() = 0;		//纯虚函数
protected:
};
void testAbstract()
{
	//Parent object;  不能构建对象
	Parent* parent = nullptr;
}

//纯虚函数就是做ADT(abstract data type 抽象数据类型)过程
//stack  栈
class stack
{
public:
	//父类中所有的操作描述好
	virtual void push(int data) = 0;
	virtual void pop() = 0;
	virtual int top() const = 0;
	virtual bool empty() const = 0;
	virtual int size() const = 0;
};
//子类想要创建对象,必须重写父类的纯虚函数
//ADT: 具有强迫性,所有子类重写函数必须和父类的一模一样
class arrayStack :public stack
{
public:
	void push(int data)
	{

	}
	void pop()
	{

	}
	int top() const
	{
		return  1;
	}
	bool empty() const
	{
		return true;
	}
	int size() const
	{
		return 1;
	}
	//可以增加别的函数
	//可以增加别的成员
protected:
	int* array;
};
struct Node
{
	int data;
	Node* next;
};
class listStack :public stack
{
public:
	void push(int data)
	{

	}
	void pop()
	{

	}
	int top() const
	{
		return  1;
	}
	bool empty() const
	{
		return true;
	}
	int size() const
	{
		return 1;
	}
protected:
	Node* headNode;
};
void testStack(stack* pStack)
{
	pStack->push(1);
	while (!pStack->empty())
	{
		cout << pStack->top();
		pStack->pop();
	}
}

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()
{
	testStack(new arrayStack);
	testStack(new listStack);
	Abtract();
	while (1);
	return 0;
}

四、虚析构函数

  • 在用子类对象初始化父类指针,父类需要虚析构函数做内存释放
#include <iostream>
#include <string>
using namespace std;

class parent
{
public:
	//虚析构函数,不存在虚构造函数
	virtual ~parent()
	{
		cout << "父类析构"<<endl;
	}
	virtual void print(){};
protected:
};
class son :public parent
{
public:
	~son()
	{
		cout << "子类析构" << endl;
	}
	void print(){}
};
int main()
{
	//在用子类对象初始化父类指针,父类需要虚析构函数做内存释放
	parent* p = new son;
	p->print();
	delete p;
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

  • 关键字final 和 override
#include <iostream>
using namespace std;

class A
{
public:
	//final禁止重写
	//子类不能存在同名函数
	virtual void print()final
	{
		cout << "重写虚函数才有的" << endl;
	}
	virtual void printData1(){}  

};
class B:public A
{
public:
	//限制子类不能写个函数
	//void print()
	//{
	//}
	//强制重写,表示作用,用检查父类中是否存在当前的虚函数
	//不存在就会报错
	virtual void printData1()override 
	{
		cout << "表示当前函数是重写的函数" << endl;
	}
};
class C :public B
{
public:
	//void print(){} 依旧不能使用
};
int main()
{
	B b;
	A a;
	a.print();
	b.print();
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

五、C++类型转换

C+类型转换,专人坐专事,传闻总C++中的更为安全。

  • const_cast
#include <iostream>
#include <string>
using namespace std;
/*
	const_cast<要转换类型>(要转换目标)
	1.去掉const属性(提供一个可以修改的接口去操作const属性的变量)
	2.加上const属性(用的比较少)
*/
class A
{
public:
	A(const char* str) :str(const_cast<char *>(str)){}
	//this->str=const_cast<char*>(str);
	void print()
	{
		cout << str << endl;
	}
protected:
	char* str;
};
class B
{
public :
	B(int num) :num(num){}
	void print()
	{
		cout << num << endl;
	}
	int num;
};
int main()
{
	const int num = 11;
	//去掉const属性
	//1.作用普通指针
	int* pNum = const_cast<int*>(&num);
	*pNum = 34;			//不能改变原来的值
	cout << num << endl;
	//2.操作类中的char*类型指针
	A aobject("1234");
	aobject.print();
	char str[] = "6666";
	A aobject2(str);
	aobject2.print();
	//3.操作类指针
	const B* pB = new B(0);
	//pB->print(); 常对象调用常成员函数
	B *ppb = const_cast<B*>(pB);
	ppb->print();
	//4.操作常量引用
	int anum;
	const int& pnum = anum;
	int & ppnum = const_cast<int &>(pnum);
	//5.加上const属性
	int a = 100;
	int *pa = &a;
	const int* ppa = const_cast<const int *>(pa);
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

  • static_cast
#include <iostream>
using namespace std;
/*
	static_cast<要转换的类型>(要转换的目标
	1.基本数据类型转换(类似C语言强制类型转换)
	2.把空指针转换成目标类型指针
	3.把任何类型的变量转换为void类型
	4.用在类上面的转换(基类和派生类对象之间的转换)
		4.1进行上行转换(从子到父 指针或者引用转换)安全
		4.2进行下行转换(从父到子 指针或者引用转换)
	注意点:是static_cast不能去掉const
*/
class  Parent
{
public:
	virtual void print()
	{
		cout << "parent"<<endl;
	}
	void printParent()
	{
		cout << "parent" << endl;
	}
};
class Son :public Parent
{
public:
	virtual void print()
	{
		cout << "son" << endl;
	}
	void printData()
	{
		cout << "son2" << endl;
	}
};
int main()
{
	//1.基本数据类型
	char cNum = 'A';
	int iNum = static_cast<int>(cNum);
	cout << iNum << endl;
	//2.空类型指针
	double* pD = new double;
	void* pVoid = static_cast<void *>(pD);
	//3.const类型转换
	int x = 10;
	const int constNum = static_cast<const int>(x);
	//4.错误用法
	const int xx = 0;
	//int* p = static_cast<int *>(&xx); 去掉从const 必须要用const_cast
	//5.从子到父
	Parent* p = new Son;
	p->print();
	Son *pson = new Son;
	p = static_cast<Parent*>(pson);
	p->print();
	//6.从父到子
	Parent *parent=new Parent;
	//son=static_cast<Son>(patent);
	Son *son=static_cast<Son*>(parent);
	son->print();
	son->printData();
	son->printParent();

	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

  • dynamic_cast
#include <iostream>
#include <string>
using namespace std;
/*
dynamic_cast<要转换类型>(要转换的东西)
1.上行转换 和static_cast一样的
2.下行转换 dynamic_cast更安全
3.交叉转换 多继承
*/
class MM
{
public:
	MM(string mmName = "父类") :mmName(mmName) {}
	virtual void print() { cout << mmName << endl; }
	string mmName;
};
class Girl :public MM
{
public:
	Girl(string gName = "子类") :gName(gName) {}
	virtual void print() { cout << gName << endl; }
	//void printData() { cout << gName << endl; }
	string gName;
};
class A
{
public:
	virtual void print()
	{
		cout << "A" << endl;
	}
};
class B
{
public:
	virtual void print()
	{
		cout << "B" << endl;
	}
};
class C :public A, public B
{
public:
	void print()
	{
		cout << "C";
	}
};


int main()
{
	MM* pM = new MM;
	Girl* pG = new Girl;
	//1.上行转换
	MM* pSM = static_cast<MM*>(pG);
	MM* pDM = dynamic_cast<MM*>(pG);
	pSM->print();
	pDM->print();
	//2.下行转换
	Girl* pSG = static_cast<Girl*>(pM);  //不存在virtual 不会报错
	//dynamic_cast检查父类中是否存在virutal
	//不存在 类型转换直接错误
	Girl* pDG = dynamic_cast<Girl*>(pM);
	pSG->print();  //不存在virtual 会中断
	//下行转换,调用子类中父类没有函数会报错
	//pSG->printData(); 
	if (pDG != nullptr)
	{
		pDG->print();
	}
	//3.交叉转换

	A* a = new C;
	B* b = dynamic_cast<B*>(a);
	b->print();
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

  • reinterpret_cast
#include <iostream>
using namespace std;
int Max(int a, int b)
{
	return a > b ? a : b;
}
int main()
{
	//将函数转换为数字
	int num = reinterpret_cast<int>(Max);
	cout << num << endl;
	cout << Max << endl;
	//将数字转换回函数
	auto pMax = reinterpret_cast<int(*)(int ,int )> (num);
	cout << pMax(1, 2) << endl;
	while (1);
	return 0;
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值