C++ 虚函数与多态 day8

本文介绍了C++中的虚函数机制,包括虚函数表和内存布局,以及纯虚函数和抽象类的概念,强调抽象类不能实例化但可作为指针或引用来使用。多态性的概念和实现方式,如上行转换和覆盖父类方法。还提到了虚析构函数在删除子类对象时的重要性。此外,讨论了final和override关键字在继承中的作用,以及从设计模式角度阐述了工厂模式如何体现多态性。
摘要由CSDN通过智能技术生成

虚函数

  • 用virtual修饰的函数叫做虚函数
  • 特性:虚函数是用一个指针去存储所有虚函数
  • 虚函数对类的影响:会增加一个指针类型的字节 (64位:8个字节,32位:4个字节)
  • 虚函数表
    在这里插入图片描述
#include <iostream>
class student
{
public:
	void virtual printA()
	{
		std::cout << "虚函数A" << std::endl;
	}
	void virtual printB()
	{
		std::cout << "虚函数B" << std::endl;
	}
protected:
	int age;
};
int main()
{
	student xiaogua;
	//因为类的对齐补齐的原因,指针占用8字节,age占用4指针,对齐补齐后占用16字节
	std::cout << "64位下的类占用字节:" << sizeof(student) << std::endl;
	//64位指针用longlong**,32位用int**
	long long** vptr = (long long**)&xiaogua;
	//定义函数指针类型的别名,语法:* 加 指针类型
	typedef void(*Func)();
	//把虚函数表的[0][0]存储值强制转换为函数指针
	Func p1 = (Func)vptr[0][0];
	p1();
	Func p2 = (Func)vptr[0][1];
	p2();
	return 0;
}
  • 运行结果
    在这里插入图片描述

纯虚函数

  • 没有函数体的函数叫做纯虚函数
  • 语法:
虚函数=0;
  • 抽象类:具有至少一个纯虚函数的类叫做抽象类
    • 不能创建对象
    • 但是可以创建对象指针
#include <iostream>
#include <string>
//抽象类
class student
{
public:
	//纯虚函数
	virtual void print() = 0;
};
int main() 
{
	//不能创建对象
	//student object;
	student* pObject = nullptr;
	return 0;
}

多态

  • C++类中对象指指针或者是引用的同一行为的不同结果,是因为初始化的对象不同导致的结果不同
  • 引发多态的情况
    • 情况一:父类指针(引用)被子类对象初始化又叫上行转换(无virtual看指针类型,有virtual看对象)
    • 情况二:必须具备同名函数并且父类中存在虚函数
    • 情况三: 一般是public继承
#include <iostream>
class student
{
public:
	void print()
	{
		std::cout << "父类:print函数" << std::endl;
	}
	void virtual printVirtual()
	{
		std::cout << "父类:printVirtual函数" << std::endl;
	}
protected:
};
class xiaogua :public student
{
public:
	void print()
	{
		std::cout << "子类:print函数" << std::endl;
	}
	//父类中有virtual子类写不写virtual都一样
	void  printVirtual()
	{
		std::cout << "子类:printVirtual函数" << std::endl;
	}

protected:
};
int main()
{
	//正常调用,都采用就近原则(看对象)
	student boy;
	xiaogua mm;
	boy.print();
	boy.printVirtual();
	//覆盖父类的方法,虽然函数名一样,但是是各自的单独
	mm.print();
	mm.printVirtual();
	std::cout << std::endl;
	//new的方法也是正常调用
	student* pB = new student;
	xiaogua* pM = new xiaogua;
	pB->print();
	pB->printVirtual();
	pM->print();
	pM->printVirtual();
	std::cout << std::endl;
	//非正常调用,子类指针初始化父类对象(上行转换)
	student* pX = new xiaogua;
	//有virtual看对象,无virtual看指针类型
	std::cout << "无virtual看指针类型:";
	pX->print();
	std::cout << "有virtual看对象:";
	pX->printVirtual();
	return 0;
}
  • 运行结果
    在这里插入图片描述

虚析构函数

  • virtual修饰的析构函数叫做虚析构函数
  • 当用子类对象初始化父类指针的时候,父类需要虚析构函数
#include <iostream>
class student
{
public:
	student()
	{
		std::cout << "构造函数student" << std::endl;
	}
	//父类指针被子类对象初始化的时候,一定要写虚析构函数
	virtual ~student()
	{
		std::cout << "析构函数student" << std::endl;
	}
protected:
};
class xiaogua :public student
{
public:
	xiaogua()
	{
		std::cout << "构造函数xiaogua" << std::endl;
	}
	~xiaogua()
	{
		std::cout << "析构函数xiaogua" << std::endl;
	}

protected:
};
int main()
{
	//父类指针被子类对象初始化的时候,一定要写虚析构函数
	student* pStu = new xiaogua;
	delete pStu;
	return 0;
}
  • 运行结果
    在这里插入图片描述

ADT:抽象数据类型

  • 抽象类的使用,抽象类不能创建的对象,但是可以创建对象指针结合子类初始化父类指针的操作
  • 继承父类的子类没有实现父类的纯虚方法,子类也是抽象类,不能构建对象
    在这里插入图片描述
#include <iostream>
class Window
{
public:
	Window() {}
	//采用成员函数的方法将pWindow加入到父类
	void push_back(Window* pWindow = nullptr)
	{
		windows[size++] = pWindow;
	}
	//框架默认的
	virtual void PressMouse()
	{
		std::cout << "默认按鼠标" << std::endl;
	}
	virtual void MouseMove()
	{
		std::cout << "默认鼠标移动" << std::endl;
	}
	//在父类中实现窗口显示
	virtual void show()
	{
		for (int i = 0; i < size; i++)
		{
			std::cout << "窗口显示:" << windows[i]->w << " " << windows[i]->h << std::endl;
		}
	}
	virtual ~Window(){}
protected:
	Window* windows[8];
	int size = 0;
	int w;
	int h;
};
class Button:public Window
{
public:
	Button() {}
	Button(int w, int h, Window* pWindow)
	{
		this->w = w;
		this->h = h;
		pWindow->push_back(this);
	}
	void MouseMove()//重写鼠标移动函数
	{
		std::cout << "画线" << std::endl;
	}
	~Button() {}
};


int main()
{
	Window* parent = new Window;
	Window* p = new Button;
	Button* button1 = new Button(100, 200, parent);
	Button* button2 = new Button(300, 400, parent);
	Button* button3 = new Button(500, 600, parent);
	p->MouseMove();
	parent->show();
	return 0;
}
  • 运行结果
    在这里插入图片描述

继承中的两个关键字

  • final:禁止重写
  • override:重写检查,检查是否是重写函数,不是直接报错
#include <iostream>
class student
{
public:
	virtual void print() final 
	{
		std::cout << "禁止重写" << std::endl;
	}
	virtual void printData() 
	{
		std::cout << "重写检查" << std::endl;
	}
protected:
};
class xiaogua:public student
{
public:
	//错误的,父类中禁止重写
	//virtual void print()
	//{
	//	std::cout << "禁止重写" << std::endl;
	//}
	// 
	//override 检查是否是重写函数,不是直接报错 
	//void printData1() override 
	//{

	//}
	void printData() override 
	{
		std::cout << "直接检查是否是重写函数" << std::endl;
	}
};
int main() 
{

	return 0;
}

拓展:从设计模式角度看待多态,工厂模式

  • 抽象工厂类
  • 具体工厂类—>创建产品
  • 提供抽象产品类
  • 具体产品类
#include <iostream>
//抽象层
class AbstractProduct
{
public:
	virtual void make() = 0;
};
//具体工厂类
class AbstractFactory
{
public:
	//创建产品
	virtual AbstractProduct* creatProduct() = 0;
};

//提供抽象产品类
class student :public AbstractProduct
{
	void make() 
	{
		std::cout << "创建学生小瓜" << std::endl;
	}

};
//具体产品类
class studentFactory :public AbstractFactory
{
public:
	AbstractProduct* creatProduct()
	{
		return new student;
	}
};

//通过增加代码的方式满足新的需求
class studentXiaoming :public AbstractProduct
{
public:
	void make()
	{
		std::cout << "创建学生小明" << std::endl;
	}
};

class studentXiaomingProduct :public AbstractFactory
{
public:
	AbstractProduct* creatProduct()
	{
		return new studentXiaoming;
	}
};
int main()
{
	AbstractFactory* factory = new studentFactory;
	AbstractProduct* studentProduct = factory->creatProduct();
	studentProduct->make();

	//通过增加代码的方式满足新的需求,不需要修改原工厂类
	factory = new studentXiaomingProduct;
	AbstractProduct* xiaoming = factory->creatProduct();
	xiaoming->make();
    return 0;
}
  • 运行结果
    在这里插入图片描述
  • 插语:
    • factory:n.工厂,制造厂;
    • product:n.产品,制品;
    • abstract:adj.抽象的,纯概念的;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值