我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++多态如何使用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++多态如何使用

本文小编为大家详细介绍“C++多态如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++多态如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

多态

多态离不开继承,首先来定义一个基类 Animal,里面有一个虚函数 speak()

class Animal {public:    Animal() = default;    Animal(string name) : m_name(name) {}    virtual ~Animal() = default;    virtual void speak() const { cout << "Animal speak" << endl; }    string name() const { return m_name; }private:    string m_name;};

接着定义子类 Dog,并重写虚函数,由于构造函数无法继承,所以使用 using 来 “继承” 父类的构造函数。和父类相比,Dog 还多了一个 bark() 方法。

class Dog : public Animal {public:    using Animal::Animal;    // 可加上 override 声明要重写虚函数,函数签名必须和基类相同(除非返回类自身的指针或引用)    void speak() const override { cout << "Dog bark" << endl; }    void bark() const { cout << "lololo" << endl; }};

向上转型

我们在堆上创建一个 Dog 对象,并将地址赋给一个 Animal 类型的指针。由于指针指向的是个 Dog 对象,调用 speak() 方法时,实际上调用的是底层狗狗重写之后的 speak() 方法,而不是基类 Animal 的 speak()。也就是说编译时不会直接确定要调用的是哪个 speak() ,要在运行时绑定。

Animal* pa = new Dog("二哈");pa->speak(); // 调用的是 Dog::speakpa->Animal::speak(); // 强制调用基类的 speak

利用运行时绑定这一特点,我们将基类的析构函数定义为虚函数,这样子类对象在析构的时候就能调用自己的虚函数了。

虽然 pa 指向的是一个 Dog 对象,但是不能使用 bark() 方法。因为 pa 是一个 Animal 类型的指针,在编译时编译器会跳过 Dog 而直接在 Animal 的作用域中寻找 bark 成员,结果发现并不存在此成员而报错。

要实现向上转型不止能用指针,引用同样可以实现。但是如果写成以下这种形式,实质上是调用了拷贝构造函数,会用 Dog 的基类部分来初始化 Animal 对象,和向上转型没有任何关系,之后调用的就是底层 Animal 对象的 speak() 方法:

Dog dog("二哈");Animal animal = dog;animal.speak(); // 调用的是 Animal::speak

向下转型

要想调用底层 Dog 对象的 bark() 方法,我们需要将 pa 强转为 Dog 类型的指针。一种方法是使用 static_cast 进行静态转换,另一种这是使用 dynamic_cast 进行运行时转换。相比于前者,dynamic_cast<type *> 转换失败的时候会返回空指针,而 dynamic_cast<type &> 则会报 bad_cast 错误,因此更加安全。

Dog* pd_ = static_cast<Dog *>(pa);pd_->bark();if (Dog* pd = dynamic_cast<Dog*>(pa)) {    pd->bark();} else {    cout << "转换失败" << endl;}

作用域

子类的作用域是嵌套在父类里面的,在子类的对象上查找一个成员时,会现在子类中查找,如果没找到才回去父类中寻找。由于作用域的嵌套,会导致子类隐藏掉父类中的同名成员。比如下述代码:

class Animal {public:    virtual void speak() const    {        cout << "Animal speak" << endl;    }};class Dog : public Animal {public:    // void speak() const override { cout << "Dog speak" << endl; }    void speak(string word) const    {        cout << "Dog bark: " + word << endl;    }};int main(int argc, char const* argv[]){    Animal* pa = new Dog();    Dog* pd = new Dog();    // pd->speak(); 报错    pd->speak("666"); // Dog::speak 隐藏了 Animal::speak    return 0;}

我们在父类中定义了一个虚函数 void speak(),子类中没有重写它,而是定义了另一个同名但是参数不同的函数 void speak(string word)。这时候子类中的同名函数会隐藏掉父类的虚函数,如果写成 pd->speak(),编译器会先在子类作用域中寻找名字为 speak 的成员,由于存在 speak(string word),它就不会接着去父类中寻找了,接着进行类型检查,发现参数列表对不上,会直接报错。如果用了 VSCode 的 C/C++ 插件,可以看到参数列表确实只有一个,没有提示有重载的同名函数。

C++多态如何使用

要想通过调用基类的 speak() 方法,有两种方法:

  • 向上转型,使用基类的指针 pa 来调用 pa->speak(),由于子类没有重写虚函数,所以在动态绑定时会调用父类的虚函数;

  • 使用作用域符强制调用父类的虚函数:pd->Animal::speak()

《C++ Primer》对名字查找做了一个非常好的总结:

理解函数调用的解析过程对于理解 C++ 的继承至关重要,假定我们调用 p->mem() (或者 obj.mem()),则依次执行以下4个步骤:

首先确定 p (或 obj) 的静态类型。因为我们调用的是一个成员,所以该类型必 然是类类型。

在 p (或 obj ) 的静态类型对应的类中查找 mem。如果找不到,则依次在直接基类中不断查找直至到达继承链的顶端。如果找遍了该类及其基类仍然找不到,则编译器将报错。

一旦找到了 mem,就进行常规的类型检查以确认对于当前找到的 mem,本次调用是否合法。

假设调用合法,则编译器将根据调用的是否是虚函数而产生不同的代码:

  • 如果mem是虚函数且我们是通过引用或指针进行的调用,则编译器产生的代 码将在运行时确定到底运行该虚函数的哪个版本,依据是对象的动态类型。

  • 反之,如果 mem 不是虚函数或者我们是通过对象(而非引用或指针)进行的调用,则编译器将产生一个常规函数调用。

读到这里,这篇“C++多态如何使用”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++多态如何使用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++多态如何使用

本文小编为大家详细介绍“C++多态如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++多态如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。多态多态离不开继承,首先来定义一个基类 Animal,里面
2023-07-02

C#多态如何实现

小编给大家分享一下C#多态如何实现,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!C#实现多态主要有3种方法,虚方法,抽象类,接口1 虚方法在父类的方法前面加关键字
2023-06-14

c++多态如何实现

多态是面向对象编程中允许对象具有不同形式或行为的一种机制。c++ 中的多态通过虚函数、抽象类、纯虚函数和动态绑定实现。虚函数允许派生类重新定义基类方法,抽象类包含必须在派生类中重新定义的虚函数,纯虚函数没有任何实现,只存在于抽象类中,而动态
c++多态如何实现
2024-04-22

Java多态数组如何使用

这篇文章主要讲解了“Java多态数组如何使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多态数组如何使用”吧!多态概述多态概念:所谓多态就是指程序中定义的引用变量所指向的具体类型和
2023-06-30

如何实现C#继承与C#多态

这篇文章主要讲解了“如何实现C#继承与C#多态”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何实现C#继承与C#多态”吧!在C#中实现OOP思想,丝毫不逊色于Java,下面我通知两句话来帮
2023-06-17

C++中的多态如何实现

这篇文章主要介绍“C++中的多态如何实现”,在日常操作中,相信很多人在C++中的多态如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++中的多态如何实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧
2023-06-30

C++中如何使用动态数组

这篇文章将为大家详细讲解有关C++中如何使用动态数组,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。C++动态数组相关操作代码如下:#include< iostream> #include
2023-06-17

C#中如何使用静态方法

C#中如何使用静态方法,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。C#静态方法使用中遇到的问题:在源码工程中几乎没有看到什么静态方法,但是在Ms的SQLHelper中几乎全部
2023-06-17

C#中如何使用静态变量

C#中如何使用静态变量,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。C#静态变量的使用实例:在类库中定义了一个静态常量,如下:public const int
2023-06-17

如何使用C++多元组Tuple

这篇文章主要讲解了“如何使用C++多元组Tuple”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用C++多元组Tuple”吧!前言tuple 是类似于pair的模板。每个pair的成
2023-06-16

Go语言多态和interface如何使用

本文小编为大家详细介绍“Go语言多态和interface如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Go语言多态和interface如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。多态的含义对于
2023-06-27

C++动态规划算法如何使用

这篇“C++动态规划算法如何使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++动态规划算法如何使用”文章吧。Fibon
2023-06-29

如何解疑C++多态覆盖问题

这篇文章给大家介绍如何解疑C++多态覆盖问题,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C++编程语言中的多态性是一个比较重要的概念,在实际应用中有许多比较重要的细节问题值得我们去关注。在这里就先来了解一下C++多态
2023-06-17

C语言中如何使用动态数组

这篇文章主要介绍“C语言中如何使用动态数组”,在日常操作中,相信很多人在C语言中如何使用动态数组问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言中如何使用动态数组”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-16

C#中静态构造函数如何使用

C#中静态构造函数如何使用,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。C#静态构造函数是一个新特性,其实好像很少用到。不过当我们想初始化一些静态变量的时候就需要用到它了。
2023-06-17

如何理解C++多态的实现过程

如何理解C++多态的实现过程,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。多态描述的是使用基类的指针或引用操作多个类型的能力。我们知道,子类的指针是可以隐式转化为父类的,所
2023-06-17

C++ 函数重载如何实现多态性?

函数重载可用于实现多态性,即通过基类指针调用派生类方法,编译器根据实际参数类型选择重载版本。示例中,animal 类定义虚拟 makesound() 函数,dog 和 cat 类重写该函数,通过 animal* 指针调用 makesound
C++ 函数重载如何实现多态性?
2024-04-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录