在C++中,inline关键字和virtual关键字分别用来定义c++中的内联函数和虚函数,他们在各自的场合都有其各自的应用,下面将简单介绍他们各自的功能,然后在说明为什么一个函数不能同时是虚函数和内联函数(inline)
- 内联函数(inline)
内联函数的目的是为了减少函数调用时间。它是把内联函数的函数体在编译器预处理的时候替换到函数调用处,这样代码运行到这里时候就不需要花时间去调用函数。但内联函数有个缺点是它会增加执行文件大小。所以如果不适当的使用内联函数会造成执行文件特别大。
而使用内联函数有以下几点需要注意:
- 头文件中不仅要包含inline函数的声明,还要包含inline函数的定义
- 编译器需要把inline函数体替换到函数调用处,所以编译器必须要知道inline函数的函数体是啥,所以要将inline函数的函数定义和函数声明一起写在头文件中,便与编译器查找替换。
- 可以在同一个项目的不同源文件内定义函数名相同,实现相同的inline函数
- 同一个inline函数可以多处声明和定义,但是必须要完全相同
- 定义在class声明内的成员函数默认是inline函数
- 虚函数(virtual)
虚函数是为了实现多态特性的。虚函数的调用只有在程序运行的时候才能知道到底调用的是哪个函数,其是有有如下几点需要注意:
- 类的构造函数不能是虚函数
- 构造函数是为了构造对象的,所以在调用构造函数时候必然知道是哪个对象调用了构造函数,所以构造函数不能为虚函数。
- 类的静态成员函数是虚函数
- 类的静态成员函数是该类共用的,与该类的对象无关,静态函数里没有this指针,所以不能为虚函数。
- 虚函数不能定义为内联函数的原因
inline是在编译器将函数类容替换到函数调用处,是静态编译的。而虚函数是动态调用的,在编译器并不知道需要调用的是父
类还是子类的虚函数,所以不能够inline声明展开,所以编译器会忽略
- 总结
- 使用inline关键字的函数可能会被编译器忽略而不在调用处展开,如虚函数。
- 如果定义的inline函数过大,为了防止生成的obj文件太大,编译器会忽略这里的inline声明
- inline是在编译器将函数类容替换到函数调用处,是静态编译的。而虚函数是动态调用的,在编译器并不知道需要调用的是父类还是子类的虚函数,所以不能够inline声明展开,所以编译器会忽略
- 头文件中不仅要包含inline函数的声明,还要包含inline函数的定义
- 编译器需要把inline函数体替换到函数调用处,所以编译器必须要知道inline函数的函数体是啥,所以要将inline函数的函数定义和函数声明一起写在头文件中,便与编译器查找替换。
- 可以在同一个项目的不同源文件内定义函数名相同,实现相同的inline函数
- 同一个inline函数可以多处声明和定义,但是必须要完全相同
- 定义在class声明内的成员函数默认是inline函数
- 类的构造函数不能是虚函数
- 构造函数是为了构造对象的,所以在调用构造函数时候必然知道是哪个对象调用了构造函数,所以构造函数不能为虚函数。
- 类的静态成员函数不能是虚函数
- 类的静态成员函数是该类共用的,与该类的对象无关,静态函数里没有this指针,所以不能为虚函数。
虚函数是为了实现动态绑定,不能声明为虚函数的有:
1、静态成员函数; 2、类外的普通函数; 3、构造函数; 4、友元函数
此外,还有一些函数可以声明为虚函数,但是没有意义,但编译器不会报错,如:
1、赋值运算符的重载成员函数: 因为复制操作符的重载函数往往要求形参与类本身的类型一致才能实现函数功能,故形参类型往往是基类的类型,因此即使声明为虚函数,也把虚函数当普通基类普通函数使用。
2、内联函数:内联函数目的是在代码中直接展开(编译期),而虚函数是为了继承后能动态绑定执行自己的动作(动态绑定),因此本质是矛盾的,因此即使内联函数声明为虚函数,编译器遇到这种情况是不会进行inline展开的,而是当作普通函数来处理。因此声明了虚函数不能实现内敛的,即内敛函数可以声明为虚函数,但是毫无了内联的意义