当前位置: 首页 > article >正文

C++虚函数与多态

C++虚函数与多态

  • 虚函数
  • 抽象类
    • 纯虚函数
  • 虚析构函数
  • 多态
  • 虚函数的几个问题
  • 纯虚函数和ADT

虚函数

virtual修饰的成员函数就是虚函数,
1.虚函数对类的内存影响:增加一个指针类型大小(32位和64位)
2.无论有多少个虚函数,只增加一个指针类型

虚函数表:指向虚函数的指针(监视的窗口看)
我们自己也可以通过虚函数指针表去访问函数(一般做这样的说数据操作,不写数据类型)

include<iostream>
#include<string>

using namespace std;


class MM
{
public:
	virtual void print()
	{
		cout << "第一个虚函数" << endl;
	}

	virtual void printDate()
	{
		cout << "第二个虚函数" << endl;
	}

private:
	int age;
	string name;
};
int main()
{
	cout << sizeof(MM) << endl;

	system("pause");
	return 0;
}


抽象类

拥有一个或一个以上的纯虚函数就被叫做抽象类
特点:
1.抽象类不能够创建对象
2.抽象类可以创建对对象指针

纯虚函数

纯虚函数也是一个虚函数,所以也需要virtual来修饰
特点:
1.纯函数没有函数体
所以函数 = 0;

#include<iostream>
#include<string>

using namespace std;


class MM
{
public:
	virtual void print() = 0; //纯虚函数

private:
	int age;
	
};
int main()
{
	//MM mm; //抽象类不能够构造对象

	MM* pmm = nullptr;

	return 0;
}


虚析构函数

在析构函数前面加一个virtual

1.当父类指针对子类对象进行初始化的时候,就要用虚析构函数
2.所有析构函数底层解析的话。函数名想相同

include<iostream>
#include<string>

using namespace std;

class MM
{
public:
	void print()
	{
		cout << "MM" << endl;
	}

	~MM()
	{
		cout << "MM析构" << endl;
	}
protected:
	string M_name;
};

class son : public MM
{
public:
	void print()
	{
		cout << "son" << endl;
	}

	~son()
	{
		cout << "son析构" << endl;
	}
};

int main()
{
	MM* p = new son; //父类指针,构造子类对象,先构造父类对象,在构造子类的对象

	delete p;

	system("pause");
	return 0;
}

在这里插入图片描述

只调用了父类的析构函数,没有调用子类的析构函数,存在内存的泄露。
所以用父类指针初始化子类的对象,必须使用虚虚构函数

#include<iostream>
#include<string>

using namespace std;

class MM
{
public:
	void print()
	{
		cout << "MM" << endl;
	}

	virtual ~MM()
	{
		cout << "MM析构" << endl;
	}
protected:
	string M_name;
};

class son : public MM
{
public:
	void print()
	{
		cout << "son" << endl;
	}

	~son()
	{
		cout << "son析构" << endl;
	}
};

int main()
{
	MM* p = new son; //父类指针,构造子类对象,先构造父类对象,在构造子类的对象

	delete p;

	system("pause");
	return 0;
}

在这里插入图片描述

多态

多态:在继承中,指针的同一行为的不同结果
多态的概念其实并不重要,重要的是,你需要知道,那个对象指针在特定情况调用那个成员。
实现多态的2个条件
1.必须是public继承
2.必须父类存在virtual类型的成员函数,并且子类中存在该函数的同名函数。
3.一定存在对象的引用

#include<iostream>
#include<string>

using namespace std;

class MM
{
public:
	void print()
	{
		cout << "MM" << endl;
	}

	virtual void printDate()
	{
		cout << "virtual printDate" << endl;
	}

	virtual ~MM()
	{
		cout << "MM析构" << endl;
	}
protected:
	string M_name;
};

class son : public MM
{
public:
	void print()
	{
		cout << "son" << endl;
	}

	void printDate()
	{
		cout << "printDate" << endl;
	}

	~son()
	{
		cout << "son析构" << endl;
	}
};

int main()
{
	//MM* p = new son; //父类指针,构造子类对象,先构造父类对象,在构造子类的对象

	//delete p;

	MM* p = new son;

      p->print();  // 没有virtual,看指针类型,这里调用的是父类的
	  p->printDate();  //有virtual,看对象,这里调用的是son的

	  p = new MM;  //调用MM 的   这就是多态
	  p->print(); 

	  //引用的类型也存在多态
	  MM mm;
	  MM& girl = mm;

	  mm.printDate();

	system("pause");
	return 0;
}

虚函数的几个问题

不管被继承几次,父类中有的虚函数,依然存在

#include<iostream>

using namespace std;


class A
{
public:
	virtual void print()
	{
		cout << "A" << endl;
	}
};

class B : public A
{
public:
};

class C : public B
{
public:
	void print()
	{
		cout << "C" << endl;
	}
	
};

int main()
{
	A* p = new C;
	p->print();

	system("pause");
	return 0;
}

在这里插入图片描述

子类实现父类虚函数的同名函数叫做:重写
final :静止重写(子类中不允许存在与之同名的虚函数)
override :强制重写,起说明作用,表示子类当前是方法是重写父类(就是说明父类中一定存在一个同名的虚函数),用于子类实现父类的同名虚函数

#include<iostream>

using namespace std;

class A
{
public:
	virtual void print() final   //final:静止重写,子类中不能够存在同名函数
	{

	}

	virtual void printDate()
	{

	}

};

class B : public A
{
public:
	void printDate() override // 强制重写,起说明作用,表示子类当前是方法是重写父类(就是说明父类中一定存在一个同名的虚函数)
	{

	}
};
int main()
{
	system("pause");
	return 0;
}

纯虚函数和ADT

ADT:抽象数据类型
注意:抽象类本身不能够创建对象,但是抽象类的子类可以创建对象
抽象类,一般用于架构项目,构建好整个项目模块,具体的细致工作,交给子类去实现

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


http://www.kler.cn/a/2464.html

相关文章:

  • RunCam WiFiLink连接手机图传测试
  • 数据结构漫游记:初识vector
  • W25Q128读写实验(一)
  • C# winform 字符串通过枚举类型转成int类型的数据
  • Redis的主从集群以及哨兵机制学习总结
  • 深入理解延迟队列:原理、实现与应用
  • ChatGPT推出第四代GPT-4!不仅能聊天,还可以图片创作!
  • 【图神经网络 文献精读】针对SARS-CoV-2大流行的改进和优化的药物再利用方案
  • 生成时序异常样本-学习记录-未完待续
  • 毕业设计 基于51单片机自动智能浇花系统设计
  • 【十二天学java】day05--数组和循环高级
  • 01 | Msyql系统架构
  • 学习系统编程No.7【进程替换】
  • 从地图到手机通讯到ChatGPT,你想要的免费 API 都给你整理好了
  • uni-app:登录与支付-- 三秒后自动跳转
  • SLF4J、Log4J、Log4J2、Logback之间是什么关系
  • 【linux】:进程控制
  • java各大集合的区别
  • 推荐一款免费开源的OCR软件
  • 菜鸟刷题Day1
  • GPIO四种输入和四种输出模式
  • 最优化算法 - 动态规划算法
  • 基于springboot的婚纱摄影网站
  • debian11安装k8s
  • Tornado 异步协程coroutine原理
  • 【K3s】第28篇 详解 k3s-killall.sh 脚本