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

为什么不在C++中将所有函数都设置为虚函数?

为什么不在C++中将所有函数都设置为虚函数?

在C++中,将所有函数都设置为虚函数并不是一个好的做法,因为这会导致一些不必要的性能开销和内存消耗。虚函数的主要目的是为了实现多态,即允许子类重写父类的方法。当一个类中的方法被声明为虚函数时,编译器会为该类生成一个虚函数表(vtable),其中包含了该类的所有虚函数的地址。当一个对象被创建时,该对象会包含一个指向虚函数表的指针,这个指针会被子类继承。当子类重写父类的虚函数时,子类的虚函数表中的相应函数地址会被替换为子类的函数地址。

将所有函数都设置为虚函数会导致以下问题:

  1. 性能开销:虚函数的调用需要通过虚函数表进行,这会导致额外的间接调用开销,增加程序的执行时间。
  2. 内存消耗:每个对象都需要包含一个指向虚函数表的指针,这会导致额外的内存消耗。
  3. 代码可读性降低:虚函数的使用会使代码变得复杂,不利于代码的可读性和维护性。

因此,在C++中,我们应该只将需要实现多态的函数设置为虚函数,而不是将所有函数都设置为虚函数。这样可以避免不必要的性能开销和内存消耗,提高程序的执行效率和代码的可读性。

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

相关·内容

构造函数为什么一般不定义函数?而析构函数一般写成函数的原因 ?

浏览量 3 1、构造函数不能声明为函数 1)因为创建一个对象时需要确定对象的类型,而函数是在运行时确定其类型的。...而在构造一个对象时,由于对象还未创建成功,编译器无法知道对象的实际类型,是类本身还是类的派生类等等 2)函数的调用需要函数表指针,而该指针存放在对象的内存空间中;若构造函数声明为函数,那么由于对象还未创建...,还没有内存空间,更没有函数表地址用来调用函数即构造函数了 2、析构函数最好声明为函数,首先析构函数可以为函数,当析构一个指向派生类的基类指针时,最好将基类的析构函数声明为函数,否则可以存在内存泄露的问题...如果析构函数不被声明成函数,则编译器实施静态绑定,在删除指向派生类的基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。子类析构时,要调用父类的析构函数吗?...析构函数调用的次序时先派生类后基类的。和构造函数的执行顺序相反。并且析构函数要是virtual的,否则如果用父类的指针指向子类对象的时候,析构函数静态绑定,不会调用子类的析构。

61110

C++】多态 ⑩ ( 不建议将所有函数声明为 virtual 函数 | 多态的理解层次 | 父类指针和子类指针步长 )

对象可以直接获取到自身封装的 普通函数 , 如果要访问函数 , 需要增加一次寻址操作 , 因此 这里建议不需要将有 多态 需求的函数声明为 函数 ; C++ 中 指向某类型对象的 指针 的 运算 ,...与 成员方法 , 那么子类指针 与 父类指针 的步长是相同的 ; 一、不建议将所有函数声明为 virtual 函数 C++ 类中 , 每个 成员函数 都可以声明为 virtual 函数 , 但是...这样会降低 运行效率 , 每次访问 成员函数 时 , 需要通过 vptr 指针获取 函数表 中的函数地址 , 显然会极大的降低效率 ; 如果 调用 非虚函数 , 可以直接通过 对象 获取到 非虚函数...virtual 函数 , 会根据实际的对象类型调用不同的 函数 , 而不是死板的调用父类的成员函数 ; 多态实现原理 : 函数 对应 动态联编 , 非虚函数 对应 静态联编 ; 有 函数...指针数据类型 : C++ 中 指针 是 数据类型 的 一种 , 对 指针 进行 自增 ++ 或 自减 – 操作 , 指针的 地址值 是根据 指针类型 改变的 ; 指针运算 : C++ 中 指向某类型对象的

24050

C++编程经验(2):基类做析构函数的必要性

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

56910

通过C++编译视频平台为什么要使用virtual析构函数

大家知道TSINGSEE青犀视频云边端架构系列编译用了几种不同的架构,同时,为了满足不同形式编译的需求,我们也会在编译当中运用到不同的函数来实现。...比如在编译中,我们使用了C++语言,为了在对象不被使用之后释放资源,函数也可实现多态,我们将函数加上了virtual。 C++中基类的析构函数为什么要用virtual析构函数?...因此,MyClass类的析构函数并没有被调用,但是正常情况下析构函数里都会释放各种资源,而析构函数不被调用的话就会导致内存泄漏。...代码1加上virtual关键字,运行次代码会调用析构函数,避免内存泄漏。 所以c++中基类采用virtual析构函数主要是为了防止内存泄漏。如果派生类中申请内存空间,而且在析构函数中对内存进行释放。...如果没有采用虚构函数,而释放该类对象,派生类对象就不会得到动态绑定。这种情况就会导致内存泄漏。所以为了防止内存泄漏,只要继承关系,被继承的类析构函数函数,都会加上virtual关键字。

53220

为什么禁止把函数参数默认值设置可变对象?

有时候我们在编写函数时,会需要给一些参数设置默认值,这个时候我们需要牢记一点:禁止使用可变对象作为参数默认值。...非常明显地提示列表[]是一个危险的默认值,这究竟是为什么呢? 为什么可变对象作为函数默认值很危险?...我们还是使用上面那个简单的“反例”,再传递几个参数,通过结果,就可以明显地看到为什么不建议我们这样做了。...这是因为Python函数的默认值只会创建一次,之后第二次调用的时候就是在原默认值上进行修改,而不是重新创建了一个新的默认值,这也就能够解释得通实际结果为什么是这样的了。...(f('3', ['1', '2'])) # 期望 -> ['1', '2', '3'] # 实际输出 ['1'] ['2'] ['3'] ['1', '2', '3'] 可以看到,把参数默认值设置不可变对象的写法就完全符合我们的预期了

1.3K30

C++核心准则C.128:函数应该明确定义virtual,overide或者final

C.128: Virtual functions should specify exactly one of virtual, override, or final C.128:函数应该明确定义...:程序员期待函数隐式成为函数而且它真的就是了(但是代码的读者看不出来);或者程序员期待函数隐式成为函数但是它不是(例如因为参数列表的微小出入);或者程序员没有期待函数成为函数但是它是了(因为它恰巧拥有和基类的某个函数相同的签名...(但是代码的读者看不出来);或者程序员期待函数隐式成为覆盖函数但是它不是(例如因为参数列表的微小出入);或者程序员没有期待函数成为覆盖函数但是它是了(因为它恰巧拥有和基类的某个函数相同的签名--注意这些问题无论函数是否被明确地声明为函数都会发生...,因为程序员本来想生成的即可能是函数,也可能是非虚函数) Enforcement(实施建议) Compare virtual function names in base and derived classes...比较基类和派生类的函数名称并且提示使用相同名称但不是override的情况。 Flag overrides with neither override nor final.

44520

C++系列笔记(五)

为此,可在基类Fish中将Swim声明为函数; class Base { virtual ReturnType FunctionName (parameter List); }; class...也就是说,如果Swim()被声明为函数,则将参数myFish(其类型Fish&)设置一个Tuna对象时,myFish.Swim()将执行Tuna::Swim(),程序如下所示: #include<...抽象基类和纯函数 不能实例化的基类被称为抽象基类,这样的基类只有一个用途,那就是从它派生出其他类。在 C++中,要创建抽象基类,可声明纯函数。...抽象基类提供了一种非常好的机制,让您能够声明所有派生类都必须实现的函数。抽象基类常被简称为ABC。ABC有助于约束程序的设计。...而构造函数只能创建固定类型的对象,不具备多态性,因此C++不允许使用复制构造函数

66430

尤玉溪回答:vue3是否汇聚所有前端开发人员的智慧删不掉ref()函数为什么svelte可以?

/master/packages/ref-transform React hooks 通过重复调用模拟 algebraic effects ,但只是在获取值的时候不需要 value,改动的时候需要调用函数...Svelte 通过分析组件 script AST 进行编译来改写你的源码,比如 a = 1 后面会插入一个 $$invalidate() 函数来通知组件。...比如你写 arr.push(1) 就不行,必须写 arr = [...arr, 1] 嵌套的函数内声明的变量就不能触发更新,也不能传递出去。 跟 hooks 一样跟组件上下文强绑定。...能够在嵌套函数内使用,并且用配套的 $$ 宏传递出去。 跟组件上下文解耦,在 ts/js 里也能使用。组件内外依然使用同一套系统,同一套语法。

77030

硬钢百度面试!

+空类的大小不为0,不同编译器设置不一样,vs和lg++都是设置1; C++标准指出,不允许一个对象(当然包括类对象)的大小0,不同的对象不能具有相同的地址; 带有函数C++类大小不为1,因为每一个对象会有一个...vptr指向函数表,具体大小根据指针大小确定; C++中要求对于类的每个实例都必须有独一无二的地址,那么编译器自动空类分配一个字节大小,这样便保证了每个实例均有独一无二的内存地址。.../ 输出 4; A a; cout<<sizeof(a)<<endl;// 输出 4; return 0; } 静态成员a不占用类的大小,所以类的大小就是b变量的大小 即4个字节 五、为什么一般构造函数定义函数...析构函数不定义函数为什么析构函数一般写函数?...所以在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生,要将基类的析构函数声明为函数为什么构造函数不写函数

17620

C++:05---class和struct

struct可以直接使用大括号对所有数据成员进行初始化 例如: 1 在C++中class和struct的区别: 在C++中对struct的功能进行了扩展,struct可以被继承,可以包含成员函数,也可以实现多态...,当用大括号对其进行初始化需要注意: 当struct和class中都定义了构造函数,就不能使用大括号对其进行初始化 若没有定义构造函数,struct可以使用{ }进行初始化,而只有当class的所有数据成员及函数...超出的部分主要有以下两方面: 1) C++对象模型本身 对于具有函数的类型来说,需要有一个方法它的实体提供类型信息(RTTI)和函数入口,常见的方法是建立一个函数入口表,这个表可为相同类型的对象共享...,因此对象中需要有一个指向函数表的指针,此外,为了支持RTTI,许多编译器把该类型信息放在函数表中。...后者依赖于不同的编译器实现,C++标准对此不做任何保证。 C++标准规定类的大小不为0,空类的大小1,当类不包含函数和非静态数据成员时,其对象大小也1。

72230

C++动态联编实现原理分析

基本的思路是: (1)每一个包含函数的类建立一个函数表,函数表的每一个表项存放的是个函数在内存中的入口地址; (2)在该类的每个对象中设置一个指向函数表的指针,在调用函数时,先采用指针找到函数表...1.指针(vptr)的存放位置 指针是作为对象的一部分存放在对象的空间中。一个类只有一个函数表,因此类的所有对象中的指针指向同一个地方。在不同的编译器中,指针在对象中的位置时不同的。...(2)指针如果不在对象的头部,那么对象h1和对象h2的头4个字节(代表整型成员变量i)的值应该是3和4。...两种方法都是利用了某种机制逃避C++的类型转换检测,为什么C++编译器干脆不直接放开这个限制,一切让程序员自己作主呢?当然是有原因的,因为类成员函数和普通函数还是有区别的,允许转换后,很容易出错。...一个类的函数有两个来源,一是继承自父类(在当前类中可能被改写),其他的是在当前类中新申明的函数。 b.所有函数排序。继承自父类的所有函数,排在当前类新生命的函数之前。

1.6K30

动态联编实现原理分析

基本的思路是: (1)每一个包含函数的类建立一个函数表,函数表的每一个表项存放的是个函数在内存中的入口地址; (2)在该类的每个对象中设置一个指向函数表的指针,在调用函数时,先采用指针找到函数表...---- 1.指针(vptr)的存放位置 指针是作为对象的一部分存放在对象的空间中。一个类只有一个函数表,因此类的所有对象中的指针指向同一个地方。...(2)指针如果不在对象的头部,那么对象h1和对象h2的头4个字节(代表整型成员变量i)的值应该是3和4。...两种方法都是利用了某种机制逃避C++的类型转换检测,为什么C++编译器干脆不直接放开这个限制,一切让程序员自己作主呢?当然是有原因的,因为类成员函数和普通函数还是有区别的,允许转换后,很容易出错。...一个类的函数有两个来源,一是继承自父类(在当前类中可能被改写),其他的是在当前类中新申明的函数。 b.所有函数排序。继承自父类的所有函数,排在当前类新生命的函数之前。

42620

QueryInterface的本质初探

为了得到该问题的答应,我们首先要分析一下C++类中的函数,以及这些函数如何在子类中被继承的。...这个实验的事实,说明了每个类对象维护一个函数表(vtbl)CTestA、CTestB以及CTestSub 维护的是不同的vtbl,每个类按类声明时函数的顺序将本类中实现的函数指针填写到自己的表中...,所以如果CTestSub 中重新实现了CTestA或CTestB中实现的函数,则在子类的函数中将用子类实现的函数地址来覆盖父类中实现的函数地址;如果子类没有实现父类中实现的函数,则表中填充的仍然是父类中实现的函数地址...;所有如果CTestSub 中不实现函数func,则CTestSub的实例sub中的表中保存的还是父类中的func函数地址,因此最终调用的就是CTestA或CTestB的func函数了。...讲到这里,大家对QueryInterface为什么会返回相同的IUnkown接口指针有所了解了吧!

36820

《逆袭进大厂》第二弹之C++进阶篇59问59答(超硬核干货)

2) 静态局部变量和全局变量一样,数据存放在全局区域,所以在主程序之前,编译器已经其分配好了内存,但在C和C++中静态局部变量的初始化节点又有点不太一样。...77、构造函数和析构函数可以调用函数吗,为什么 1) 在C++中,提倡不在构造函数和析构函数中调用函数; 2) 构造函数和析构函数调用函数时都不使用动态联编,如果在构造函数或析构函数中调用函数,...2) 析构函数顺序 ① 调用派生类的析构函数; ② 调用成员类对象的析构函数; ③ 调用基类的析构函数。 79、析构函数的作用,父类的析构函数是否要设置函数?...而构造函数是在创建对象时自动调用的,不可能通过父类或者引用去调用,因此就规定构造函数不能是函数 (4)析构函数一般都要声明为函数,这个应该是老生常谈了,这里不再赘述 《为什么C++不能有虚构造函数,...④ 恢复被调用者寄存器当中的值,这一过程其实是从栈帧中将备份的值再恢复到寄存器,不过此时这些值可能已经不在栈顶了 ⑤ 恢复被调用者寄存器当中的值,这一过程其实是从栈帧中将备份的值再恢复到寄存器,

2.3K40

计算机基础方向规划 | CPP

函数机制的理解,单继承、多继承、继承条件下函数表的结构 如果函数是有效的,那为什么不把所有函数设为函数? 构造函数可以是函数吗?析构函数可以是函数吗? 什么场景需要用到纯函数?...怎么用C++在编码层面尽量避免内存泄漏。 unique_ptr如何转换所有权? 谈一谈你对面向对象的理解 什么场景下使用继承方式,什么场景下使用组合?...C++之难不在于其语法的复杂性,也不在于二进制层面上语义的杂乱无章,更不在于玄妙得不食人间烟火的模板推导(模板元编程),这些都只是表象。...13、sizeof与strlen对比 14、指针与引用的区别 15、野指针产生与避免 16、多态:动态多态、静态多态 17、函数实现动态多态的原理、函数与纯函数的区别 18、继承时,父类的析构函数是否函数...构造函数能不能为函数为什么

61150

D语言的陷阱

前面都好理解,但是连成员函数默认是public,这就奇怪了。从OOP的角度来说,默认应该是保护级别的最大级别,尤其是在类中。在C++中,成员函数默认是private,这跟数据封装有关系。...至于D为什么要把成员函数默认为public,俺不理解。另外俺认为良好的编程风格应该可以清晰表达代码的意图。D为了保持C/C++的观感,采取了上面的风格。俺不推荐。...因此,我们重点考察D的方法调用和多接口继承(应用设计模式,抽象类也能发挥很大作用,但不在我们讨论范围之内)。...D语言的方法调用机制跟Java很相似,却与C++/C#背道而驰(这两种设计哲学孰优孰劣不予讨论)。D认为,所有非静态,非私有方法默认都是方法。需要说明的是,方法调用的开销要比非虚方法调用大的多。...因此,D编译器在编译代码之前,会分析子类是否overridden父类的方法。如果没有,则编译成非虚方法。这样做的好处是不用再考虑应该把哪个方法设置方法了,坏处是可能造成设计的不清晰和滥用。

59710

计算机基础方向规划 | CPP

函数机制的理解,单继承、多继承、继承条件下函数表的结构 如果函数是有效的,那为什么不把所有函数设为函数? 构造函数可以是函数吗?析构函数可以是函数吗? 什么场景需要用到纯函数?...怎么用C++在编码层面尽量避免内存泄漏。 unique_ptr如何转换所有权? 谈一谈你对面向对象的理解 什么场景下使用继承方式,什么场景下使用组合?...C++之难不在于其语法的复杂性,也不在于二进制层面上语义的杂乱无章,更不在于玄妙得不食人间烟火的模板推导(模板元编程),这些都只是表象。...13、sizeof与strlen对比 14、指针与引用的区别 15、野指针产生与避免 16、多态:动态多态、静态多态 17、函数实现动态多态的原理、函数与纯函数的区别 18、继承时,父类的析构函数是否函数...构造函数能不能为函数为什么

60830
领券