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 语句这样不仅输入量减少,而且代码也美观多了代码也主次分明了毕竟。

你可能感兴趣的:(C++知识,c++,开发语言,面试)