我有一个类角度与<<运算符重载和两个包含头文件的cpp文件。我有一个#ifndef语句来防止文件被多次包含。但是,似乎它被包含多次,因为我得到了一个错误,即运算符<<被定义了多次。然后我添加了一个#warning satement来查看文件的包含时间。在编译器输出中可以看到#warning被处理两次。如果我将定义移动到cpp文件,它显然有效,但我仍然觉得这种情况下的行为很奇怪。
在我看来,编译器不应该两次处理头文件。这种行为有原因吗?
的main.cpp
#include <iostream>
#include <cmath>
#include <cstdlib>
#include "Angle.h"
using namespace std;
int main() {
Angle a = (Angle)(M_PI/4);
cout << a << endl;
return EXIT_SUCCESS;
}
Angle.h
#ifndef ANGLE_ANGLE_H
#define ANGLE_ANGLE_H
#include <iostream>
class Angle {
private:
double value;
public:
explicit Angle (double value) {this->value = value; }
double getValue() const {return this->value;}
// Operators
operator const double() const {
return this->value;
}
};
#warning INCLUDING_ANGLE_H
std::ostream& operator << (std::ostream& os, const Angle& obj){
os << obj.getValue();
return os;
}
#endif //ANGLE_ANGLE_H
Angle.cpp
#include "Angle.h"
我正在使用以下命令进行编译:
g++ main.cpp Angle.cpp -o angle
出现以下错误:
In file included from main.cpp:5:0:
Angle.h:19:2: warning: #warning INCLUDING_ANGLE_H [-Wcpp]
#warning INCLUDING_ANGLE_H
^
In file included from Angle.cpp:1:0:
Angle.h:19:2: warning: #warning INCLUDING_ANGLE_H [-Wcpp]
#warning INCLUDING_ANGLE_H
^
/tmp/cci53Hrd.o: In function `operator<<(std::ostream&, Angle const&)':
Angle.cpp:(.text+0x0): multiple definition of `operator<<(std::ostream&, Angle const&)'
/tmp/ccBbwtlD.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
答案 0 :(得分:2)
问题不在于标题包含两次,而是函数定义了两次。在.cpp文件中定义它,并在标题中的前向声明中添加extern,一切都应该有效。问题是,每次包含头时,它都会创建一个新的函数实现,并且您将收到一个链接器错误,它不知道要使用哪个。这就是为什么你不应该在头文件中实现全局函数,而是在.cpp。
中实现你的Angle.h将有:
extern std::ostream& operator << (std::ostream& os, const Angle& obj);
而Angle.cpp将具有:
std::ostream& operator << (std::ostream& os, const Angle& obj){
os << obj.getValue();
return os;
}
答案 1 :(得分:0)
编译时多次包含头文件是完全正常的。 #ifndef
只会阻止相同编译过程中的多个包含,即相同的.cpp
文件。
编译阶段通常将多个.cpp
文件编译为中间形式,稍后将其链接到一个库或可执行文件中。
如果您需要为每个目标定义一次该函数,则必须将该代码移动到单个.cpp
文件中。将其包含在标题中可能会导致重复。