重复定义问题

这里说的重复定义其实包含两个意思:

1,头文件重复包含

2,变量或函数重复定义

对问题1,比如这样:

有一个头文件 c.h 。

在头文件a.h中

#include "c.h"

在头文件b.h中

#include "a.h"

#include "c.h"

这样就会导致重复包含,解决办法如下:

在c.h中

#ifndef C_H
#define C_H

//c.h中所有内容

#endinf

这样,在第二次引用"c.h"时,由于已经定义了C_H,将不会再次引用"c.h"

当然,也要避免在头文件里include,如果include是写在cpp里面的话,就不会出现相互包含导致编译出错的问题,但是!!!!!如果头文件里的函数写了实现,重复包含的话仍然是要出错的,具体看问题2的解释

 

对于问题2:

如果在c.h中,有一个函数实现,比如:

int integer_add(const int a, const int b)
{
  return a+b;   
}

在a.cpp和b.cpp中都包含的c.h,那么编译的时候:

a.cpp编译得到a.obj,b.cpp编译得到b.obj;

在链接时期,a.obj和b.obj和运行库连接起来生成可执行文件的时候,就会冲突,因为两个obj里都有一份integer_add的函数实现,导致链接器不知道对于调用者,应该使用哪一个副本

解决办法:

1.使用inline修饰函数

使用inline,意味着编译器会在调用此函数的地方把函数的目标代码直接插入,而不是放置一个真正的函数调用,也就是说这个函数实际上已经不再存在,而是像宏一样被就地展开了。

除了体积变大,使用inline还有这样的问题:inline严格来算不是关键字,inline是对编译器进行请求而不是强制,所以在一些特殊情况下,编译器并不会真正使用inline进行修饰

类函数在类定义的时候就实现的情况下,缺省就是inline的

模板函数也是相似的

2.使用static修饰函数

使用static意味着,所有包含此头文件的源文件中都会存在此函数的一份副本,代码也有一定膨胀,但是相互不冲突,因为static关键字保证了该函数可见度为单个源文件

通过static修饰类函数,就可以使用这样的调用方式:Integer::add(i,j);

 

对于virtual函数,它总是生成一份代码,即使你显式使用inline关键字修饰,因为:virtual函数地址会被写到类的v-table里,在运行期才被调用。

 

对于类被多个cpp包含的情况下,没有出现冲突,原因是遵守“单一定义规则”(One_Definition Rule, ODR) :如果对同一个类的两个定义完全相同且出现在不同编译单元,会被当作同一个定义

 

 相关引用:

链接1;

关于内联更具体的分析

const和inline

内联函数使用注意

posted on 2019-01-05 17:27  YoungBig  阅读(1879)  评论(0编辑  收藏  举报

导航