一文解密C++中的多态机制

 更新时间:2023年07月31日 14:07:33   作者:Aomnitrix  
众所周知C++语言的三大特性:封装、多态、继承,其中多态就是去完成某个行为,但是会根据不同的对象产生不同的状态,下面小编就来带大家深入了解一下C++的多态机制吧

一.多态

1.多态的用处

众所周知C++语言的三大特性:封装、多态、继承。其中多态就是去完成某个行为,但是会根据不同的对象产生不同的状态,所以叫多态。

2.多态的实现

在继承中实现多态还需要两个条件:

1.使用基类的指针或者引用来调用虚函数

2.必须在派生类对虚函数进行重写

代码演示如下:

class A
{
public:
	virtual void func()
	{
		cout << "A::func()" << endl;
	}
};
class B : public A
{
public:
	void func()
	{
		cout << "B::func()" << endl;
	}
};
int main()
{
	B b;
	A& a = b;
	a.func();
	return 0;
}

3.虚函数

用virtual修饰的类成员函数叫做虚函数,虽然与虚拟继承用的是同一关键字但是两者并无关联。

virtual void func(){cout << "A::func()" << endl;}

派生类的重写:

重写需要在派生类中编写与基类相同的虚函数:返回类型相同(协变除外)、函数名相同、参数相同(缺省值可不同),然后函数具体实现的不同,来完成多态。

协变

协变允许基类派生类虚函数的返回值不同,但是要求返回值是互为父/子类的指针或者引用。如下所示:

class A
{
public:
	A(int a = 1)
		:_a(a) {}
	virtual A* func(int val = 0)
	{
		cout << val<< endl;
		return new A;
	}
private:
	int _a;
};
class B : public A
{
public:
	B(int b = 1)
		:_b(b) {}
	virtual B* func(int val = 1)
	{
		cout << val<< endl;
		return new B;
	}
private:
	int _b;
};
int main()
{
	B b;
	A& a = b;
	a.func();
	return 0;
}

上图中,如果返回的不是本身自己父子类的指针/引用,则可以交换顺序!需要注意的是在派生类重写基类的虚函数可以不加virtual

析构函数的重写

如果基类重写的析构函数,在派生类可以不加virtual也可以完成重写(因为编译器将析构函数的名称统一处理成destructor。)

4.override 和 final

这两个关键字都是C++11的新语法,final修饰虚函数 使得虚函数不可以重写

override 可以在派生类函数检查是否重写的基类虚函数,如果没有就 报错

如果不想类被继承可以采用:将构造函数设为私有、将类用final修饰为最终类

5.重载重写与重定义

重载:两个函数在同一作用域、函数名/参数相同

重写:两个函数分别在基类和派生类的作用域、函数名/参数/返回值都必须相同(协变例外)、两个函数必须是虚函数

隐藏(重定义)两个函数分别在基类和派生类的作用域、函数名相同、两个基类和派生类的同名函数不构成重写就是重定义

6.虚函数表

如果在类中定义了虚函数,那么类中就会有个虚表用来存放虚表指针。

虚函数表本质是一个存虚函数指针的指针数组

虚表中存放着虚函数,同类型对象会共用一块虚表。

子类自己的虚函数只会放到第一个父类的虚表后面,其他父类的虚表不需要存储,因为存储了也不能调用

有虚函数的类前4/8字节存储的是虚表的地址。

去虚表找 看是什么对象 (多态时)

虚函数重写只重写函数的实现 缺省值会使用父类的

到此这篇关于一文解密C++中的多态机制的文章就介绍到这了,更多相关C++多态机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现手写红黑树的示例代码

    C语言实现手写红黑树的示例代码

    红黑树在表意上就是一棵每个节点带有颜色的二叉搜索树,并通过对节点颜色的控制,使该二叉搜索树达到尽量平衡的状态。本文主将用C语言实现手写红黑树,需要的可以参考一下
    2022-09-09
  • 构造函数不能声明为虚函数的原因及分析

    构造函数不能声明为虚函数的原因及分析

    构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我们可能通过实验室的基类的指针或引用去访问它但析构却不一定,我们往往通过基类的指针来销毁对象
    2013-10-10
  • C++ vector模拟实现的代码详解

    C++ vector模拟实现的代码详解

    vector是表示可变大小数组的序列容器,就像数组一样,vector也采用的连续存储空间来存储元素,本质讲,vector使用动态分配数组来存储它的元素,本文将给大家详细介绍一下C++ vector模拟实现,需要的朋友可以参考下
    2023-07-07
  • Qt中JSON使用的详细步骤

    Qt中JSON使用的详细步骤

    本文主要介绍了Qt中JSON使用的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • C语言 格式化读写文件详解

    C语言 格式化读写文件详解

    本文主要介绍C语言 格式化读写文件,这里提供了关于格式化读写文件的基本资料及实现示例代码,有兴趣的小伙伴可以参考下,以便理解学习
    2016-08-08
  • C语言中数组常用的一些排序算法小结

    C语言中数组常用的一些排序算法小结

    数组的排序方法有很多,效率也各不相同,下面这篇文章主要给大家介绍了关于C语言中数组常用的一些排序算法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-01-01
  • Qt实现实时鼠标绘制图形

    Qt实现实时鼠标绘制图形

    这篇文章主要介绍了Qt中QGraphicsView架构下如何实现实时鼠标绘制图形,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试
    2022-02-02
  • C++使用cjson操作Json格式文件(创建、插入、解析、修改、删除)

    C++使用cjson操作Json格式文件(创建、插入、解析、修改、删除)

    本文主要介绍了C++使用cjson操作Json格式文件(创建、插入、解析、修改、删除),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C++获取任务栏打开程序窗口示例

    C++获取任务栏打开程序窗口示例

    这篇文章主要介绍了C++获取任务栏打开程序窗口,大家可以参考使用
    2013-11-11
  • C语言线程对象和线程存储的实现

    C语言线程对象和线程存储的实现

    这篇文章主要介绍了C语言线程对象和线程存储的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03

最新评论