首页 > 编程语言 >【C++】虚函数与多态

【C++】虚函数与多态

时间:2022-12-26 16:56:19浏览次数:44  
标签:调用 函数 派生类 多态 C++ func 基类

所谓多态,简单来讲就是指,不同的子类在继承父类后分别都重写覆盖了父类的方法。

例如下例中:

class A {
    public:void f() {
            cout << "这是A中的func" << endl;
        };
};
class B: public A { public:void f() { cout << "这是B中的func" << endl; } };

如果我们调用 A a; a.f(); ,那么调用的就是A类中的f函数;如果我们调用 B b; b.f(); ,那么调用的就是B类中的f函数;如果我们调用 A a = B(); a.f(); ,结果也仍然会是调用A类中的f函数。

而有时候,一个基类会有很多派生类,这些派生类中也许会出现很多功能相似、名称相同的函数,如果手动去调用就会非常麻烦,我们希望的是能写一个函数,这个函数能统一帮我们调用传入对象中对应的那个函数,换句话来说,对于基类A的派生类BCDEF......如果存在那么一个函数,在我们想调用某个类中的某个同名函数时,能够自动帮我们对应到相应函数,也就是实现多态,就会方便很多。

这时就需要借助虚函数了。

虚函数,听这个名字就感觉它是虚的,事实上也可以这么理解,如果我们将基类中的一个同名函数定义为虚函数,那么,当使用基类引用或基类指针去调用派生类对象的同名函数时,它就会自动调用派生类中的同名函数。虽然这样说起来似乎是理所当然,毕竟调用的就是派生类中的函数,出现这样的结果似乎很好理解,但是注意,我们上述的例子已经表明,在没有定义虚函数的情况下,即使你使用基类引用或者基类指针,也调用不到派生类的同名函数,它能接触到的仅仅是基类的函数。

也就是说,虚函数只是提供了一个桥梁,当计算机通过基类指针或引用去调用这个函数,却发现它是虚函数时,它就会去检查是否在这个派生类中存在一个同名的函数,有就去调用它,所以可以说基类中的这个函数是被架空、覆盖的,一般不会被调用。

声明虚函数的关键字是 virtual ,注意,虚函数只需要在基类中声明就行了,派生类中的同名函数都不需要再声明。

我们来看下面这个例子:

#include <bits/stdc++.h>
using namespace std;
class A {
    public:
        virtual void f() {
            cout << "这是A中的func" << endl;
        };
};
class B: public A {
    public:void f() {
            cout << "这是B中的func" << endl;
        }
};
class C: public B {
    public:
        void f() {
            cout << "这是C中的func" << endl;
        }
};
void test_ref(A & a)
{
    a.f();
}
void test_ptr(A * a)
{
    a->f();
}
int main()
{
    A a;
    B b;
    C c;
    a.f(); b.f(); c.f();
    test_ref(a); test_ref(b); test_ref(c);
    test_ptr(&a); test_ptr(&b); test_ptr(&c);
    return 0;
}

在上示代码中,我们将基类A中的f函数定义为虚函数,派生类B和C中也分别存在一个同名函数。然后我们定义了两个函数,这两个函数用来实现多态,它们一个使用基类指针调用f函数,一个使用基类引用调用,其结果都是一样的。在主函数中,我们先分别使用普通的对象调用方式调用一遍f函数,然后再使用函数调用。

运行结果为:

这是A中的func
这是B中的func
这是C中的func
这是A中的func
这是B中的func
这是C中的func
这是A中的func
这是B中的func
这是C中的func

从最后的结果可以看出,明明是同一个函数,传入不同类的对象,调用同一个函数,得到的结果却不一样,它自动对应到了相应的那个函数,显然比手动调用要方便很多。

最后,我们还要弄清楚一个区别,上面我们使用了基类指针和基类引用实现了虚函数的调用,那么问题就来了,能不能使用基类对象来调用虚函数。

其实这个问题的答案要看你是怎么理解的,通常来讲,我们调用虚函数是希望实现多态,但是,用基类对象能调用虚函数,无法实现多态。

例如,我们将上面的 test_ref 函数中的形参改为 A a ,然后再在主函数中分别传入类A B C的实例化对象a b c,结果为:

这是A中的func
这是A中的func
这是A中的func

也就是说,如果选择用基类对象调用虚函数,那么你永远只能调用到基类的虚函数,所以,调用是能调用的,只是没办法实现多态。

标签:调用,函数,派生类,多态,C++,func,基类
From: https://www.cnblogs.com/codas/p/17006183.html

相关文章

  • 【C++入门】(四)数组
    一. 一维数组1.1 数组的定义//数组的定义方式和变量类似。#include<iostream>#include<algorithm>usingnamespacestd;intmain(){inta[10],b[10];......
  • 1、C++环境与编译
    C++环境与编译章节概览我们将在本章讨论以下内容:a.什么是一个程序(抽象与实现)b.什么是程序的程序的开发环境c.什么是程序的编译d.什么是IDE、compiler、assembler、li......
  • C++项目中编译部分C的代码
    在C++项目中如果真能编译部分C的代码,那么一定会用到一下语句#ifdef__cplusplusextern"C"{#endif/*...*/#ifdef__cplusplus}#endif下面......
  • C++强化 | 06 一篇文章带你掌握字符数组
    导读数组是信息学中非常重要的一块内容,可以说是必备的,也几乎是信息学竞赛中写代码必用的。前面的三节课,我们讲了一维数组,让大家对一维数组有了更加全面深刻的认知。本篇文章......
  • ts12_构造函数
     构造函数,会在对象创建时调用,new关键字会执行constructorclassDog{name:string;age:number;//构造函数,会在对象创建时调用,new关键字会执行construct......
  • 普林斯顿微积分读本02第一章--函数的复合、奇偶函数、函数图像
    函数的复合:接着还是复习函数相关的基础,“函数的复合”,这个从字面意思也比较好理解,就是一个函数是由多个函数复合而成嘛,下面来具体看一下书本对它的介绍。假设有这么一个函......
  • [Note]生成函数
    普通生成函数常用于解决组合问题。对于无穷数列\(a\),生成函数即为\(f(x)=\sum_{i=0}^{∞}a_ix^i\)。容易发现一个显然的性质:若\(c_i=a_i+b_i\),那么有\(f_c(x)=f_a(......
  • 『DL笔记』深入理解softmax交叉熵损失函数反向传播求导过程分析
    目录​​一、softmax函数​​​​二、损失函数lossfunction​​​​三、最后的准备工作                         ......
  • linux文件操作函数
    前言:    我们在这一节将要讨论linux下文件操作的各个函数.文件的创建和读写文件的各个属性目录文件的操作管道文件----------------------......
  • c++开机自动启动程序
    为了让程序开机自动启动,找了一些网上资料终于实现。voidHKRunator(){charprogramName[MAX_PATH]={0};DWORDdwRet=GetModuleFileName(NULL,(LPSTR)p......