一文带你掌握C++虚函数·和多态

9. C++虚函数与多态

虚函数

virtual修饰的成员函数就是虚函数

  • 虚函数对类的内存影响:需要增加一个指针类型的内存大小
  • 无论多少虚函数,只会增加一个指针类型的内存大小
  • 虚函数表的概念: 指向虚函数的指针

我们自己也可以通过虚函数表指针去访问函数(一般做这样的操作不写数据类型)

#include <iostream>
#include <string>
using namespace std;
class MM 
{
public:
	virtual void print() 				//1.会写
	{
		cout << "第一个虚函数" << endl;
	}
	virtual void printData() 
	{
		cout << "第二个虚函数" << endl;
	}
protected:

};
int main() 
{
	cout << sizeof(MM) << endl;   	//2.对类内存影响
	MM mm;
	mm.print();
	mm.printData();
	//了解一下.32位没问题,64位 vs2022 问题
	int** pObject = (int **)(&mm);
	typedef void(*PF)();
	PF pf = (PF)pObject[0][0];
	pf();						//调用第一个虚函数
	pf = (PF)pObject[0][1];
	pf();						//调用第二个虚函数
	return 0;
}

纯虚函数

具有一个或者多个纯虚函数的类型称之为抽象类,抽象类特性:

  • 抽象类不能创建对象
  • 抽象类可以创建对象指针

纯虚函数也是一个虚函数,所以也需要virtual修饰,纯虚函数是没有函数体,函数=0;

#include <iostream>
using namespace std;
//抽象类
class MM 
{
public:
	//纯虚函数
	virtual void print() = 0;
protected:
	string name;
};
int main() 
{
	//MM object;   抽象类不能构建对象
	MM* pMM = nullptr;
	return 0;
}

虚析构函数

virtual修饰的析构函数 就是虚析构函数

  • 当父类指针被子类对象初始化的时候需要用虚析构函数
  • 所有析构函数底层解析其实函数名相同

#include <iostream>
#include <string>
using namespace std;
class MM 
{
public:
	void print() 
	{
		cout << "MM::print" << endl;
	}
	virtual ~MM()					//虚析构函数
	{
		cout << "~MM" << endl;
	}
};
class Son :public MM 
{
public:
	void print() 
	{
		cout << "Son::print" << endl;
	}
	~Son() 
	{
		cout << "~Son" << endl;
	}
};

int main() 
{
	MM* pMM = new Son;   //构造子类对象,必须构造父类对象在构造自身
	pMM->print();		 //MM看类型
	delete pMM;
	pMM = nullptr;
	return 0;
}

虚函数和多态

多态的概念并不重要,重要的是需要知道那个对象指针在特定情况调用那个成员才是重要

多态概念: 指在继承中指针的同一行为的不同结果,举个栗子(男生和女生上厕所,都是上厕所的行为,男生站着,女生蹲着)

实现多态的两个前提条件:

  • 必须是public继承
  • 必须父类存在virtual类型的成员函数,并且子类中存在该函数的同名函数
  • 一定存在指针的引用
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
	void print()
	{
		cout << "MM::print" << endl;
	}
	virtual void printData() 
	{
		cout << "MM virtual printData" << endl;
	}
	virtual ~MM()					//虚析构函数
	{
		cout << "~MM" << endl;
	}
};
class Son :public MM
{
public:
	void print()
	{
		cout << "Son::print" << endl;
	}
	void printData() 
	{
		cout << "Son printData" << endl;
	}
	~Son()
	{
		cout << "~Son" << endl;
	}
};
int main() 
{
	//正常对象的访问,不存在多态
	//都是就近原则
	cout << "正常对象访问" << endl;
	MM mmobject;
	mmobject.print();
	mmobject.printData();
	Son sonobject;
	sonobject.print();
	sonobject.printData();
	//正常的指针访问
	cout << "正常指针访问" << endl;
	MM* pMM = new MM;
	pMM->print();
	pMM->printData();
	Son* pSon = new Son;
	pSon->print();
	pSon->printData();
	//非正常的初始化
	//父类指针被子类初始化
	cout << "不正常的指针赋值" << endl;
	MM* pObject = new Son;
	pObject->print();				//没有virutal 看指针类型 调用MM::print
	pObject->printData();			//有virtual 看对象 调用Son::printData
	pObject = new MM;
	pObject->printData();			//调用MM中
	
	cout << "引用类型" << endl;
	MM& girl = sonobject;
	girl.print();
	girl.printData();

	return 0;
}

虚函数在继承特殊现象

#include <iostream>
#include <string>
using namespace std;
class A
{
public:
	virtual void print()
	{
		cout << "A" << endl;
	}
	virtual void printData() final   //禁止子类重写方法
	{
		cout << "A" << endl;
	}
};

//final: 父类中用来禁止子类重写同名方法
//override: 强制重写,起说明作用,表示当前子类当前方法是重写父类
class B :public A 
{
public:
	//重写:子类实现父类虚函数的同名函数
	void print() override
	{
		cout << "B" << endl;
	}
	//void printData(){}  //final禁止重写
};
class C :public B 
{
public:
	void print() 
	{
		cout << "C" << endl;
	}
};
int main() 
{
	B* pb = new C;
	pb->print();			//调用C::print
	pb = new B;
	pb->print();			//调用B::print
	return 0;
}

纯虚函数和ADT

ADT: 抽象数据类型

抽象类本身不能创建对象,但是子类如果重写类父类中纯虚函数,子类是可以被允许创建对象

抽象类一般用于架构项目,构建好整个项目模块,具体细致工作可以交给子类去实现

采用ADT方式设计项目,可以把这个模块构建出来,并且测试代码也可以提前完成。

#include <iostream>
using namespace std;

//抽象产品类
class AbstractProduct 
{
public:
	virtual void printProduct() = 0;
};
//抽象系统类---ADT
//析构函数一定写虚析构函数
class AbstractSystem 
{
public:
	~AbstractSystem() {}
	virtual void insertData(AbstractProduct* product) = 0;
	virtual void printData()const = 0;
	virtual int size() const = 0;
	virtual bool empty() const = 0;
};

class ArraySystem :public AbstractSystem 
{
public:
	void insertData(AbstractProduct* product) 
	{
	}
	void printData()const 
	{
	}
	int size() const 
	{
		return 0;
	}
	bool empty() const 
	{
		return 0;
	}
};
class ListSystem :public AbstractSystem
{
public:
	void insertData(AbstractProduct* product)
	{
	}
	void printData()const
	{
	}
	int size() const
	{
		return 0;
	}
	bool empty() const
	{
		return 0;
	}
};
int main() 
{
	AbstractSystem* p =new  ArraySystem;
	p->printData();
	//UI中用的比较多
	//MFC --->不需要自己创建,只需要重写一个,构建对象即可

	p = new ListSystem;
	p->printData();
	return 0;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值