我好像一直以来都以为编译链接的时候,在头文件里用了条件编译#ifndef #define #endif 或pragma once 就不会出现multiple definition of xx 的问题,直到昨天… 情形如下,我在头文件里定义了一个函数而不是声明,然后两个cpp文件都include 了这个头文件,最后链接的时候就出现了以上问题。因为对编译的理解不够才导致了这个问题。 头文件如下:
#ifndef HEADER_H
#define HEADER_H
#include <iostream>
#include <string>
using namespace std;
void print(string &message) { cout << message << endl; }
#endif
cpp1如下:
#include "header.h"
void fun() { print("hello world"); }
main.cpp如下:
#include "header.h"
extern void fun();
int main() {
fun();
return 0;
}
编译器每次编译一个文件时都会把include 的头文件包括进来,所以在编译cpp1时,会定义一个print 的函数;在编译main时,又定义一个print 的函数,其实这时还没有产生错误。当我们链接这两个编译后的文件之后,才产生了多次定义错误。根据下图也能看到是链接器报错。
为什么fun 函数没有报错? 因为在main里我是声明了fun 函数,在编译时编译器就知道别处有这样一个函数,在链接的时候看到cpp1里定义了fun 函数,于是把main的fun符号重定位到cpp1的fun 函数,所以最后调用的是cpp1定义的fun 函数(这里链接时链接器是如何做的我不是很清楚)
头文件被包含多次时tips:
- 用const修饰的变量会默认对其他cpp文件不可见,所以在头文件里定义了
const int a = 1 并多次包含这个头文件不会保错。 - 对于类来说,似乎写在头文件class x{};括号里的内容都不产生这种错误。如下:
#ifndef HEADER_H
#define HEADER_H
#include <iostream>
#include <string>
using namespace std;
class A {
void print(){} //no error
};
#endif
如果定义在类外同时在头文件中,会产生错误。如下:
#ifndef HEADER_H
#define HEADER_H
#include <iostream>
#include <string>
using namespace std;
class A {
void print();
};
void A::print(){} //error
#endif
|