inline内联函数为什么不能是虚函数?

这篇具有很好参考价值的文章主要介绍了inline内联函数为什么不能是虚函数?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. inline内联函数为什么不能是虚函数?

虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联
理由如下:内联是在发生在编译期间,编译器会自主选择内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。 inline virtual唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 Base::who()),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。

2. 编译器对inline函数的处理步骤
  • 将 inline 函数体复制到 inline 函数调用点处;
  • 为所用 inline 函数中的局部变量分配内存空间;
  • 将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中;
  • 如果 inline 函数有多个返回点,将其转变为 inline 函数代码块末尾的分支(使用 GOTO);
3. 类模板、函数模板与虚函数?
4. 为什么要避免头文件重复包含呢
  1. 在编译c或c++程序时候,编译器首先要对程序进行预处理,预处理其中一项工作便是将源程序中 #include的头文件完整的展开,如果多次包含相同的头文件,会导致编译器在后面的编译步骤多次编译该头文件,工程代码量小还好,工程量一大会使整个项目编译速度变的缓慢,后期的维护修改变得困难。
  2. 第一点讲的头文件重复包含的坏处其实还能忍,但是头文件重复包含带来的最大坏处是会使程序在编译链接的时候崩溃。

那么如何避免它呢?

通常有两种做法:条件编译和**#pragma once**。

区别:

  1. #ifndef 是通过定义独一无二的宏来避免重复引入的,这意味着每次引入头文件都要进行识别,所以效率不高。但考虑到 C 和 C++ 都支持宏定义,所以项目中使用 #ifndef 规避可能出现的“头文件重复引入”问题,不会影响项目的可移植性。
  2. 和 ifndef 相比,#pragma once 不涉及宏定义,当编译器遇到它时就会立刻知道当前文件只引入一次,所以效率很高。但值得一提的是,并不是每个版本的编译器都能识别 #pragma once 指令,一些较老版本的编译器就不支持该指令(执行时会发出警告,但编译会继续进行),即 #pragma once 指令的兼容性不是很好

注意#pragma once 只能作用于某个具体的文件,而无法向 #ifndef 那样仅作用于指定的一段代码。

5. 声明与定义

**“声明”:**只是声明某个符号(变量或函数)的存在,即告诉编译器,这个符号是在其他文件中定义的,我这里先用着,你链接的时候再到别的地方去找找看它到底是什么吧。

**“定义”:**则是要按C++语法完整地定义一个符号(变量或者函数),告诉编译器在此处分配存储空间建立变量和函数。

**头文件的作用:**就是被其他的.cpp包含进去的, 本身并不参与编译。但实际上,它们的内容却在多个.cpp文件中得到了编译。通过"定义只能有一次”的规则,很容易可以得出:头文件中应该只放变量和函数的声明,而不能放它们的定义。因为一个头文件的内容实际上是会被引 入到多个不同的.cpp文件中的,并且它们都会被编译。放声明当然没事,如果放了定义,那么也就相当于在多个.cpp文件中出现了对同一个符号(变量或函数)的定义,因此就会报“重复定义的错误”。

**总结:**声明是将一个名称引入程序;定义提供了一个实体(类型、变量、对象、函数)在程序中的唯一描述。

**所以:**一个符号,在整个程序中可以被声明多次,但只允许被定义一次。

6. 内部链接与外部链接

1. 内部链接:内部链接意味着对符号名的访问仅限于当前编译单元。即:对于任何其他编译单元都是不可见的,在链接的时候不会与其它编译单元中同样的名称相冲突,则这个符号具有内部链接。

具体有

  1. 静态(static)全局变量的定义、静态自由函数的定义、静态友元函数的定义;
  2. 类的声明与定义;
  3. 内联函数定义;
  4. Union共同体/结构体/枚举类型定义;
  5. const常量定义;
  6. 各种声明;

C++又补充规定,extern const联合修饰时,extern将压制const的内部链接属性。

用内部链接定义的一个重要的例子就是类的定义。类的定义如下。因此,它不能够在同一作用域的编译单元内重复定义。如果需要在其他编译单元使用,类必须被定义在头文件且被其他文件包含。仅仅在其他文件中使用class Point;声明是不行的,原因就是类的定义是内部链接,不会在目标文件导出符号。也就不会被其他单元解析它们的未定义符号。

class Point{
     int d_x;                             // 内部链接
     int d_y;
  public:
     Point(int x,int y):d_x(x),d_y(y){}   // 内部链接
     int x() const{return d_x;}           // 内部链接
     int y() const{return d_y;}           // 内部链接
};

因此:具有内部链接的符号无法作用于当前文件外部,要让其影响程序的其他部分,可以将其放在.h文件中。此时在所有包含此.h文件的源文件都有自己的定义且互不影响。

2. 外部链接:外部链接意味着这个定义不局限于单个的编译单元。在.o文件中,具有外部链接的定义产生外部符号,这些外部符号可以被所有其他编译单元访问,用来解析其他编译单元中未定义的符号,即:一个名称在链接时可以和其他编译单元交互,那么这个名称就具有外部链接。

因此:因此它们在整个程序中必须是唯一的,否则将会导致重复定义

​ 具体有:

​ 1.类的非内联函数(包括成员函数和静态成员函数)的定义
​ 2.类的静态成员变量的定义
​ 3.名字空间或全局非静态的自由函数,非静态变量,非友元函数的定义

 class A
 {
     static int a;       // 类的静态成员声明,内部链接
     void fun();         // 类的非内联成员函数声明,内部链接
     static void fun2(); // 类的非内联静态成员函数声明,内部链接
     void fun2(){...};   // 类内实现函数定义,若为内联则为内部链接,若为非内联则为外部链接
 }
 int A::a = 1;           // 类的静态成员定义,外部链接
 void A::fun(){...};     // 类的非内联成员函数定义,外部链接
 static void A::fun2(){...}; //类的非内联静态成员函数定义,外部链接

 namespace A{...}  // 名字空间定义,外部链接
 void fun3(){...}; // 全局非静态自由函数定义,外部链接
 int b;            // 全局非静态变量,外部链接

所以,拥有外部链接的实体如果放在头文件中并且被多个.cpp文件包含,可能就会出现链接冲突错误,因为每个包含这个拥有外部链接实体的.cpp都会分配空间,当多个编译单元链接的时候,连接器就会面对多个相同的名字,无法正常链接到正确的对象。

因此:由于cpp文件中存储的是成员函数的实现,而成员函数具有外部链接特性,会在目标文件产生符号。在此文件中此符号是定义过的。其他调用此成员函数的目标文件也会产生一个未定的符号。两目标文件连接后此符号就被解析。

判断一个符号是内部链接还是外部链接的一个很好的方法就是看该符号是否被写入.o文件,由于声明只对当前编译单元有用,因此声明并不将任何东西写入.o文件。

宏是内部链接还是外部链接

都不是,宏在预处理环节时就被替换掉了,而内部链接与外部链接是针对编译环节与链接环节而言的

7. 在.h中和.cpp中include头文件有什么区别

在 .h 里面 include 的好处是:如果全部在一个.h, 那么每个.c/.cpp文件只需要一个#include 语句这样不仅输入量减少,而且代码也美观多了代码也主次分明了毕竟。文章来源地址https://www.toymoban.com/news/detail-832165.html

到了这里,关于inline内联函数为什么不能是虚函数?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 为什么分类问题不能使用mse损失函数,更容易理解版本

    分类问题通常不适合使用均方误差(Mean Squared Error,MSE)损失函数,原因如下: 输出差异的度量不同:MSE损失函数是基于预测值和真实值之间的差异的平方和进行计算的,适用于回归问题(建立一个模型来预测连续数值输出的问题, eg: 房价预测;股票价格预测…),其中

    2024年04月26日
    浏览(31)
  • Inline内联函数简单理解

    How to Write it? example- 特点 编译器会将函数调用直接展开为函数体代码 人话: 直接将函数体里面的计算方法直接放到函数调用里,类似于宏替换。和#include 很像,但不相同。 编译后代码体量会变大。 用途 因为调用普通函数需要 开辟栈空间 ,调用完成后要 回收栈空间 如果是内

    2024年03月11日
    浏览(41)
  • 【C++】初阶 --- 内联函数(inline)

    🥰 用C语言先来实现普通的Add函数看一下 👇 转到反汇编来看一下: 可以看到,编译器为了实现一个简单的相加函数,Add函数体内需要执行的汇编指令要很多,而且为了调用函数还要执行指令跳转 (并且要在栈区上为函数开辟栈帧空间) ,如果 Add函数被重复大量地使用,则会

    2024年02月14日
    浏览(33)
  • 为什么 volatile不能保证原子性

    volatile 本质上是一种内存屏障,它可以确保在 volatile 变量写操作和读操作之间不会发生重排序,这样就可以保证对 volatile 变量的修改能够立即对其他线程可见。但是, volatile 只能保证可见性,并不能保证原子性。 在 Java 中,原子性是指一个操作是不可中断的,即使在

    2024年02月15日
    浏览(53)
  • 为什么sessionStorage不能代替vuex

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 译为“会话存储”,也是HTML5新增的一个存储对象, 用于本地临时存储同一窗口的数据,在 关闭窗口之后 将会删除这

    2024年02月09日
    浏览(64)
  • STM32为什么不能跑Linux?

    STM32是一系列基于ARM Cortex-M微控制器的产品,它们主要用于嵌入式系统中。而Linux则是一个开源的类Unix操作系统,主要面向的是桌面电脑、服务器等资源丰富的计算机。虽然理论上可以将Linux移植到STM32上运行,但是由于两者之间存在着很多技术差异,导致在实际使用中面临着

    2024年04月10日
    浏览(62)
  • 【C++】内联函数----inline函数的详细使用教程

    🌹作者:云小逸 📝个人主页:云小逸的主页 📝Github:云小逸的Github 🤟motto:要敢于一个人默默的面对自己, 强大自己才是核心 。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天

    2024年02月04日
    浏览(45)
  • 为什么MySQL单表不能超过2000万行?

    摘要: MySQL一张表最多能存多少数据? 本文分享自华为云社区《为什么MySQL单表不能超过2000万行?》,作者: GaussDB 数据库 。 最近看到一篇《我说MySQL每张表最好不要超过2000万数据,面试官让我回去等通知》的文章,非常有趣。 文中提到,他朋友在面试的过程中说,自己的

    2024年02月05日
    浏览(50)
  • 【PDF密码】PDF文件不能打印,为什么?

    正常的PDF文件是可以打印的,如果PDF文件打开之后发现文件不能打印,我们需要先查看一下自己的打印机是否能够正常运行,如果打印机是正常的,我们再查看一下,文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功能按钮以及打印按钮都是灰色的状态,那就证

    2024年02月13日
    浏览(58)
  • springboot~InvocationHandler中为什么不能使用@Autowired

    @Autowired 是 Spring Framework 中用于自动注入依赖的注解,通常情况下可以正常工作,但有一些情况下可能无法获取到 bean 对象: Bean未定义或未扫描到 :如果要注入的 bean 没有在 Spring 上下文中定义或者没有被正确扫描到, @Autowired 将无法找到要注入的 bean。确保你的 bean 配置正

    2024年02月10日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包