虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。
理由如下:内联是在发生在编译期间,编译器会自主选择内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。 inline virtual
唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 Base::who()
),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。
那么如何避免它呢?
通常有两种做法:条件编译和**#pragma once**。
区别:
注意:#pragma once 只能作用于某个具体的文件,而无法向 #ifndef 那样仅作用于指定的一段代码。
**“声明”:**只是声明某个符号(变量或函数)的存在,即告诉编译器,这个符号是在其他文件中定义的,我这里先用着,你链接的时候再到别的地方去找找看它到底是什么吧。
**“定义”:**则是要按C++语法完整地定义一个符号(变量或者函数),告诉编译器在此处分配存储空间建立变量和函数。
**头文件的作用:**就是被其他的.cpp包含进去的, 本身并不参与编译。但实际上,它们的内容却在多个.cpp文件中得到了编译。通过"定义只能有一次”的规则,很容易可以得出:头文件中应该只放变量和函数的声明,而不能放它们的定义。因为一个头文件的内容实际上是会被引 入到多个不同的.cpp文件中的,并且它们都会被编译。放声明当然没事,如果放了定义,那么也就相当于在多个.cpp文件中出现了对同一个符号(变量或函数)的定义,因此就会报“重复定义的错误”。
**总结:**声明是将一个名称引入程序;定义提供了一个实体(类型、变量、对象、函数)在程序中的唯一描述。
**所以:**一个符号,在整个程序中可以被声明多次,但只允许被定义一次。
1. 内部链接:内部链接意味着对符号名的访问仅限于当前编译单元。即:对于任何其他编译单元都是不可见的,在链接的时候不会与其它编译单元中同样的名称相冲突,则这个符号具有内部链接。
具体有:
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文件。
宏是内部链接还是外部链接
都不是,宏在预处理环节时就被替换掉了,而内部链接与外部链接是针对编译环节与链接环节而言的
在 .h 里面 include 的好处是:如果全部在一个.h, 那么每个.c/.cpp
文件只需要一个#include
语句这样不仅输入量减少,而且代码也美观多了代码也主次分明了毕竟。