首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

beginner c ++:基类中的虚函数

在C++中,基类中的虚函数是一种特殊的成员函数,它允许在派生类中重写它们。这意味着,当您使用基类指针或引用指向派生类对象时,可以调用派生类中的实现,而不是基类中的实现。

虚函数的定义方法是在函数声明前加上 virtual 关键字。例如:

代码语言:c++
复制
class Base {
public:
    virtual void foo() {
        // 基类中的实现
    }
};

class Derived : public Base {
public:
    void foo() override {
        // 派生类中的实现
    }
};

在上面的例子中,Base 类中的 foo 函数被声明为虚函数,因此当您使用 Base 类的指针或引用指向一个 Derived 类的对象时,可以调用 Derived 类中的 foo 函数实现,而不是 Base 类中的实现。

虚函数的主要优点是它们允许您在不影响现有代码的情况下扩展类的功能。例如,如果您有一个基类和许多派生类,您可以在基类中定义一个虚函数,然后在每个派生类中重写它以提供特定于该类的实现。这样,当您使用基类指针或引用指向派生类对象时,您可以调用派生类中的实现,而不是基类中的实现。

总之,虚函数是C++中一种非常有用的特性,它们允许您在不影响现有代码的情况下扩展类的功能。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

C++

---- 摘自《C++程序设计》 如果一个派生有多个直接,而这些直接又有一个共同,则在最终派生中会保留该间接共同数据成员多份同名成员。...C++提供(virtual base class)方法,使得在继承间接共同时只保留一份成员。 ---- 下面举例说明: 在如下图中: ?...Person是Student和Teacher,而Graduate又继承自Student和Teacher。...但是显示,这我不是我们希望,同样副本我们只需要一份。所以C++中提出了实现方式。...声明一般形式是: class 派生名:virtual 继承方式 名称 下面是上面实例代码: 声明person.h: #pragma once #include

61410

c++继承 派生 函数

参考链接: C++继承 继承    关系有组合、继承和代理。继承本质就是代码复用。子类继承父一些东西,父也称为,子类也称为派生。派生继承了除构造函数以外所有成员。 ...1.调用构造函数 2.调用派生构造函数 派生析构可想而知: 1.调用派生析构函数 2.调用析构函数  函数  如下程序:  class Base { public:     Base...中含有函数,那么布局存在一个函数指针,指向函数表;且其派生与其同名同参函数不需要加virtual也是函数。...vfptr指针指向vftable(函数表),&Base_meta存放了RTTI信息(运行时类型信息),也就是class Base,0表示偏移,&Base::Show表示函数入口地址。...首先通过指针所指向对象找到vfptr,再找到vftable,获取到Show函数入口地址,此时 &Derive::Show存放是派生函数入口地址,因此调用是派生Show()函数

1K20

C++

如果一个派生有多个直接,而这些直接又有一个共同,则在最终派生中会保留该间接共同数据成员多份同名成员。C++提供方法,使得在继承间接共同时只保留一份成员。...现在,将A声明为,方法如下: class A//声明基A {…}; class B :virtual public A//声明B是A公用派生,A是B {…}; class...C :virtual public A//声明CA公用派生,A是C {…}; 注意: 并不是在声明基时声明,而是在声明派生时,指定继承方式时声明。...因为一个可以在生成一个派生时作为,而在生成另一个派生时不作为。...可以看到A构造函数被调用了两遍!下面我们把A改成再看看结果。

1.1K20

派生多态函数

C++语言中,必须将它两种成员函数区分开来: 一种是希望其派生进行覆盖函数 另一种是希望派生直接继承而不要改变函数。 对于前者,通常将其定义为函数(virual)。...任何构造函数之外非静态函数都可以是函数。 关键字virtual只能出现在内部声明语句之前而不能用于外部函数定义。 如果把一个函数声明成函数,则该函数在派生也是函数。...成员函数如果没被声明为函数,则其解析过程发生在编译时而非运行时。就会按照实际情况调用。 派生可以继承定义在成员,但是派生成员函数不一定有权访问从继承而来成员。...此外,我们能将公有派生类型对象绑定到引用或指针上。 大多数都只继承自一个,这种形式继承被称作“单继承”。 派生函数派生类经常(但不总是)覆盖它继承函数。...如果派生没有覆盖其某个函数,则该函数行为类似于其他普通成员,派生会直接继承其在版本,派生可以在它覆盖函数前使用virtual关键字,但不是非得这么做(可有可无)。

13820

C++虚拟继承与

1.多重继承带来问题 C++虚拟继承一般发生在多重继承情况下。C++允许一个有多个父,这样就形成多重继承。...(1)当在多条继承路径上有一个公共,在这些路径某几条汇合处,这个公共就会产生多个实例(或多个副本),若只想保存这个一个实例,可以将这个公共说明为,就像Student和Employee...(2)被虚拟继承,叫做实际指的是继承方式,而非一个,是动词,而非名词。 (3)为了实现虚拟继承,派生对象大小会增加4。...(4)虚拟继承对象是由最远派生构造函数通过调用构造函数进行初始化,派生构造函数成员初始化列表必须列出对构造函数调用;如果未列出,则表示使用该缺省构造函数。...因为虚拟继承只是表名某个对象在派生对象只被构造一次,而在本例Student和Employee对象在EGStudent对象本来就不会被构造多次,所以不将它们申明也是完全可以

85320

C++编程经验(2):为析构函数必要性

这个要提一下,如果记不住就记住:如果不做析构函数,会有内存泄漏 解释 定义一个指针p,在delete p时,如果析构函数函数,这时只会看p所赋值对象,如果p赋值对象是派生对象,...就会调用派生析构函数;如果p赋值对象是对象,就会调用析构函数,这样就不会造成内存泄露。...如果析构函数不是函数,在delete p时,调用析构函数时,只会看指针数据类型,而不会去看赋值对象,这样就会造成内存泄露。 多少学点设计模式就清楚了。...接下来是一个子类 class Inherit :public Base{ //此处省去,一切从简 }; //重点看调用 int main() { Base *p = new Inherit; //这种方式调用...,这时候有没有析构就不一样了 delete p; Base *q = new Base; delete q; return 0; }

55610

【Example】C++ 继承 (菱形继承问题)

这时,Base 便成了 Byte 和 Expert ,达成了继承方式,Base 在最终 Blu 只存在一个,所以不存在命名空间冲突及资源浪费。...并不是“绝对”,而是“相对”:在它自身声明、定义时候无需任何修饰,只是在子类继承时进行 virtual 修饰。...所以在 Blu 仍然存在菱形继承问题,所有需要将所有继承同一上级父继承方式声明为 virtual。...同时,在继承机制当中,是由最终派生进行初始化,本身达成了一种 “间接继承” 关系。 也就意味着最终派生在构造函数初始化,要在初始化表调用构造函数进行初始化。...private privat privat private private 另外,继承概念:【Example】C++ 继承 (菱形继承问题) 继承时,子类内存结构当中不包含父

87330

菱形继承问题及解决方法—继承与C++)

菱形继承 菱形继承概念 两个派生继承同一个,又有某个类同时继承着这两个派生 菱形继承典型案例 这种继承带来问题主要有两方面: 羊和驼都继承了动物成员,当羊驼想要使用时,会产生二义性...很明显羊驼从羊和驼两个父各自继承了一份m_Age,通过限定作用域方式无法彻底解决这个问题,这个时候就要使用继承 继承与 具体实现为在羊和驼继承前加上virtual关键词,...Animal称为 代码如下: #include using namespace std; class Animal // { public: int m_Age...可以看出羊和驼数据只是一个指针,并未继承具体数据,这个指针指向各自表,而存在一个偏移量,通过这个偏移量再加上首地址可以找到数据,所以实际上羊驼只继承了一份数据...(也就是那份)。

97740

C++核心准则C.35:析构函数要么是公开函数,要么是保护非虚函数

C.35: A base class destructor should be either public and virtual, or protected and nonvirtual 析构函数要么是公开函数...如果析构函数时保护,那么调用侧代码就无法通过类型指针销毁派生对象,这是析构函数就没有必要一定是函数。析构函数是保护而不是私有的,这样派生析构函数才能调用它。...通常,设计者不会知道在析构函数应该执行什么样动作。...我们可以想象一种需要保护函数析构函数情况:当希望允许派生对象(只有这个类型)通过指针销毁另外一个对象(不是它自己)时。但是我们还没有在实际开发遇到这种情况。...拥有函数函数要么是公开函数,要么是保护非虚函数。 译者注:拥有函数一般就意味着它有派生

1K20

C++】多态 ⑧ ( 验证指向 函数 vptr 指针 | 对比定义了函数和没有定义函数大小 )

存储到 " 函数表 " ; 函数表 创建 : 在 中使用 virtual 关键字 声明 函数 时 , C++ 编译器 会自动为该类生成 " 函数表 " ; 生成函数前提是 至少有...1 个函数 ; 如果 没有函数 , 就不会生成函数表 ; 如果 中有 virtual 函数 , 则 该类 每个对象 , 都有一个 指向 函数 vptr 指针 ; 函数表 存储...函数指针 : " 函数表 " 是 存储 " 成员函数指针 " 数据结构 , 是一个 函数指针数组 , 数组元素都是函数指针 , 具体存储都是 指向 函数 指针 ; 如果 子类... , 重写了 父 virtual 函数 , 那么 C++ 编译器会在 子类 函数表 中放入该 子类函数 函数指针 ; 如果 C++ 存在 virtual 函数 , 在创建对象时 ,...; 2、函数与普通函数对比 - 多出了 vptr 指针大小 下面的代码 , 定义了 2 个 , 区别是 一个定义了 virtual 函数 , 另外一个没有定义 函数 ; 在 Parent

17440

干货丨C++函数

C++函数作用主要是实现了多态机制。关于多态,简而言之就是用父类型别的指针指向其子类实例,然后通过父指针调用实际子类成员函数。...这样,在有函数实例这个表被分配在了 这个实例内存,所以,当我们用父指针来操作一个子类时候,这张函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用函数。...多重继承(无函数覆盖) 下面,再让我们来看看多重继承情况,假设有下面这样一个继承关系。注意:子类并没有覆盖父函数。 ? 对于子类实例函数表,是下面这个样子: ?...下图中,我们在子类覆盖了父f()函数。 ? 下面是对于子类实例函数图: ? 我们可以看见,三个父函数f()位置被替换成了子类函数指针。...对一个C++,如果它要呈现多态(一般编译器会将这个以及它是否存在virtual关键字作为这个是否要多态),那么会有一个virtual function table,而每一个实例(对象)

52541

从零开始学C++之继承(三):多重继承、继承与

,更好软件重用 可能会有大量二义性,多个可能包含同名变量或函数 多重继承解决访问歧义方法: 名::数据成员名(或成员函数(参数表)) 明确指明要访问定义于哪个成员...二、继承与 当派生从多个派生,而这些又从同一个派生,则在访问此共同成员时,将产生二义性,可以采用来解决。...此时只有一份weigh_,不存在访问歧义问题。 从输出可以总结出: 1、成员是由最远派生构造函数通过调用构造函数进行初始化。...2、在整个继承结构,直接或间接继承所有派生,都必须在构造函数成员初始化表给出对构造函数调用。如果未列出,则表示调用该默认构造函数。...3、在建立对象时,只有最远派生构造函数调用构造函数,该派生其他构造函数调用被忽略。

1K00

C++纯函数与抽象

定义,定义函数一般形式为: virtual 函数返回值类型 函数名(形参表) { 函数体 } 为什么说函数C++最重要特性之一呢,因为函数承载着C++动态联编作用,也即多态...在继承体系,构造顺序就是从到派生,其目的就在于确保对象能够成功地构建。构造函数同时承担着函数建立,如果它本身都是函数的话,又如何确保函数成功构建呢?...1.2析构函数继承析构函数一般都是函数。当中有函数时候,析构函数也要定义为析构函数。...一般情况下,如果类没有函数,就不用去声明析构函数。当且仅当里包含至少一个函数时候才去声明析构函数。只有当一个被用来作为时候,才有必要将析构函数写成函数。...2.纯函数与抽象 既然有了函数,那为什么还需要有纯函数呢?在Java编程语言中有接口定义,在C++虽然没有接口关键字,但是纯函数就完成了接口功能。

1.4K20

从零开始学C++之函数与多态(二):纯函数、抽象析构函数

一、纯函数 函数是实现多态性前提 需要在定义共同接口 接口要定义为函数 如果接口没办法实现怎么办?...如形状Shape 解决方法 将这些接口定义为纯函数不能给出有意义函数定义,这时可以把它声明成纯函数,把它定义留给派生来做 定义纯函数: class 名{        ...构造函数不能是函数,析构函数可以是函数 1、抽象不能用于直接创建对象实例,可以声明抽象指针和引用 2、可使用指向抽象指针支持运行时多态性 3、派生必须实现函数,否则它仍将被看作一个抽象...#include  using namespace std; // 对于一个没有任何接口,如果想要将它定义成抽象,只能将析构函数声明为纯 // 通常情况下在函数不需要实现...如果想要将它定义成抽象,只能将析构函数声明为纯 // 通常情况下在函数不需要实现 // 例外是纯析构函数要给出实现。

1.3K00

C++进阶:详解多态(多态、函数、抽象以及函数原理详解)

C++进阶:详解多态(多态、函数、抽象以及函数原理详解) 结束了继承介绍:C++进阶:详细讲解继承 那紧接着肯定就是多态啦 1.多态概念 多态是指同一个函数名可以根据调用对象不同而具有不同实现...在进行函数重写时,子类函数返回值类型、函数名、参数列表必须与函数完全相同 注意:在重写函数时,派生函数在不加virtual关键字时,虽然也可以构成重写(因为继承后函数被继承后在派生依旧保持函数属性...,上面也是一个经典场景——使用多态时,通过指针删除派生对象 2.3C++11里 override 和 final final:用于在派生阻止对函数进一步重写,或者在定义阻止被继续派生...nullptr(这个也是看平台) 总结一下派生表生成: 先将表内容拷贝一份到派生 如果派生重写了某个函数,用派生自己函数覆盖函数 派生自己新增加函数按其在派生声明次序增加到派生最后...因此,对象函数调用会绑定到函数表上,而无法访问派生函数

17810
领券