C++虚函数和多态超详细分析

 更新时间:2023年01月20日 08:51:00   作者:king&南星  
这篇文章主要介绍了C++多态的特性派生与虚函数与模板,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

1.什么是虚函数

C++类中用virtual修饰的函数叫做虚函数,构造函数没有虚构造函数,存在虚析构函数,C++所有虚函数都是一个指针去存储的,所以具有虚函数的类,内存会增加一个指针大小的内存

#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
	//虚函数指针是同一个,所以无论该类中有多少个虚函数,
	//占用的内存就只是一个指针的大小
	virtual void print()
	{
		cout << "我是第一个虚函数" << endl;
	}
	virtual void printData() 
	{
		cout << "我是第二个虚函数" << endl;
	}
protected:
};
class son:public MM
{
public:
	void print() 
	{
		//该函数也是虚函数,
        //父类中同名函数是虚函数
		//所以子类该函数也是虚函数
	}
protected:
};
int main() 
{
	cout << sizeof(MM) << endl;
	cout << "...................." << endl;
	//虚函数表的理解,下面带图解
	MM mm;
	long long** p = (long long**)&mm;
	using Func = void(*)();
	Func f1 = (Func)p[0][0];
	Func f2 = (Func)p[0][1];
	f1();
	f2();
	return 0;
}

2.纯虚函数

纯虚函数也是虚函数的一种,只是没有函数体,下面请看怎么表示没有函数体

纯虚函数——>虚函数=0;

具有一个或者多个虚函数的类叫做抽象类

  • 抽象类不能构建对象
  • 但是可以构建函数指针
#include<iostream>
using namespace std;
class MM
{
public:
	virtual void print() = 0;
};
int main()
{
	//MM mm; //抽象类不能构建对象
	MM* pmm = nullptr;
	return 0;
}

3.c++多态

多态指的是因为指针的不同的赋值操作所导致的同一行为的不同结果。多态的这个概念东西不太重要,重要的是什么样的情况调用什么样的行为

  • 正常指针和正常对象调用行为,就近原则
  • 父类指针被子类对象初始化
  • 函数有virtual看对象类型
  • 函数没有virtual看指针类型
  • final关键字 禁止子类重写父类方法
  • override显示说明当前函数是重写函数

多态三个必要性条件:

  • 父类中存在虚函数
  • 存在不正常指针的引用(不正常赋值关系)
  • public继承
#include<iostream>
using namespace std;
class MM
{
public:
	void print()
	{
		cout << "父类" << endl;
	}
	virtual void printData()
	{
		cout << "MM" << endl;
	}
};
class son :public MM 
{
public:
	void print() 
	{
		cout << "子类" << endl;
	}
	void printData() 
	{
		cout << "son" << endl;
	}
};
int main()
{
	MM* pmm = new son;
	pmm->print();
	pmm->printData();
	return 0;
}

4.纯虚函数和ADT过程

ADT:abstract data type抽象数据类型,主要是通过继承抽象类中,子类必须要实现父类的抽象方法,子类才可以创建对象。

#include<iostream>
#include<string>
using namespace std;
class data
{
public:
	string name;
	int age;
};
class MM
{
public:
	virtual bool empty() = 0;
	virtual int size() = 0;
};
class List:public MM
{
public:
	bool empty()
	{
		return 0;
	}
	int size()
	{
		return NULL;
	}
};
int main()
{
	MM* pmm = new List;
	pmm->empty();
	pmm->size();
}

5.虚析构函数

virtual修饰的析构函数就是虚析构函数,当存在子类对象初始化父类指针的时候,父类析构函数就要是虚析构函数,否则只会释放父类,存在内存泄漏问题

#include<iostream>
using namespace std;
class MM
{
public:
	virtual ~MM()
	{
		cout << "父类" << endl;
	}
};
class son:public MM
{
public:
	~son()
	{
		cout << "子类" << endl;
	}
};
int main()
{
	MM* pmm = new son;
	delete pmm;
	return 0;
}

6.dynamic_cast类型转换

  • 上行转换 子类到父类 和staic_cast差不多
  • 下行转换 父类到子类 dynamic_cast更为安全
  • 交叉转换 多继承
#include<iostream>
using namespace std;
class MM
{
public:
	virtual void print() { cout << "MM" << endl; }
};
class son:public MM
{
public:
	void print() { cout << "son" << endl; }
};
class A
{
public:
	virtual void print(){}
};
class B
{
public:
	virtual void print() {}
};
class C:public A,public B
{
public:
	void print()
	{
		cout << "c" << endl;
	}
};
int main()
{
	MM* partent = new MM;
	son* Son = new son;
	//上行转换----->没有必要
	MM* p = static_cast<MM*>(Son);
	MM* pp = dynamic_cast<MM*>(Son);
	MM* ppp = Son;       //可以
	//下行转换
	son* x = dynamic_cast<son*>(partent); //安全,父类没有virtual会报错---->多态
	if(!x)
	{
		printf("error");
	}                           //下行转换不安全,不会申请成功
	A* a = new A;
	B* b = dynamic_cast<B*>(a);
	b->print();
	return 0;
}

7.成员函数指针

#include<iostream>
#include<functional>
using namespace std;
class MM
{
public:
	void print() { cout << "king" << endl; }
	static void printData() { cout << "MM" << endl; }
};
int main()
{
	void(*p)() = &MM::printData;
	p();
	//必须通过对象调用
	void(MM::*pp)() = &MM::print;
	MM mm;
	(mm.*pp)();
	//函数适配器,让函数调用形态可以适用于别的形态
	auto f = bind(&MM::print, &mm);
	f();
	return 0;
}

到此这篇关于C++虚函数和多态超详细分析的文章就介绍到这了,更多相关C++虚函数和多态内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Visual Studio 2022无法打开源文件的解决方式

    Visual Studio 2022无法打开源文件的解决方式

    这篇文章主要介绍了Visual Studio 2022无法打开源文件的解决方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • C++ odr用法案例详解

    C++ odr用法案例详解

    这篇文章主要介绍了C++ odr用法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • 数据结构之带头结点的单链表

    数据结构之带头结点的单链表

    单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:数据域(数据元素的映象) + 指针域(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据
    2023-07-07
  • C++泛型编程基本概念详解

    C++泛型编程基本概念详解

    这一篇介绍一下 C++ 编程中与面向对象并列的另一大分支——泛型编程,这一篇主要介绍函数模板、类模板和成员模板三大部分,需要的朋友可以参考下
    2021-08-08
  • C++实现动态线性表

    C++实现动态线性表

    这篇文章主要为大家详细介绍了C++实现动态线性表,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • Qt编写地图实现实时动态轨迹效果

    Qt编写地图实现实时动态轨迹效果

    实时动态轨迹主要是需要在地图上动态显示GPS的运动轨迹,也是编写地图时一个重要的功能。本文将利用Qt实现这一功能,需要的可以参考一下
    2022-02-02
  • C++之拼接长字符串问题

    C++之拼接长字符串问题

    这篇文章主要介绍了C++之拼接长字符串问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Qt界面美化之自定义qss样式表的详细步骤

    Qt界面美化之自定义qss样式表的详细步骤

    很多人应该和我一样,想做界面才接触的Qt,结果就是做不出来华丽的界面,下面这篇文章主要给大家介绍了关于Qt界面美化之自定义qss样式表的详细步骤,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-03-03
  • C++语法中的函数重载和默认参数

    C++语法中的函数重载和默认参数

    这篇文章主要介绍了C++语法中的函数重载和默认参数,本文从语法角度通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • C语言 超详细模拟实现单链表的基本操作建议收藏

    C语言 超详细模拟实现单链表的基本操作建议收藏

    单链表是后面要学的双链表以及循环链表的基础,要想继续深入了解数据结构以及C语言,我们就要奠定好这块基石!接下来就和我一起学习吧
    2022-03-03

最新评论