c – 头文件中的多重定义

给出这个代码示例:

复合体

#ifndef COMPLEX_H
#define COMPLEX_H

#include <iostream>

class Complex
{
public:
   Complex(float Real, float Imaginary);

   float real() const { return m_Real; };

private:
   friend std::ostream& operator<<(std::ostream& o, const Complex& Cplx);

   float m_Real;
   float m_Imaginary;
};

std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {
   return o << Cplx.m_Real << " i" << Cplx.m_Imaginary;
}
#endif // COMPLEX_H

complex.cpp:

#include "complex.h"

Complex::Complex(float Real, float Imaginary) {
   m_Real = Real;
   m_Imaginary = Imaginary;
}

main.cpp:

#include "complex.h"
#include <iostream>

int main()
{
   Complex Foo(3.4, 4.5);
   std::cout << Foo << "\n";
   return 0;
}

编译此代码时,会收到以下错误信息:

multiple definition of operator<<(std::ostream&, Complex const&)

我发现使这个功能内联解决了问题,但我不明白为什么。为什么编译器抱怨多重定义?我的头文件被保护(使用#define COMPLEX_H)。

而且,如果抱怨操作者<<功能,为什么不抱怨公共real()函数,这也是在标题中定义的? 除了使用inline关键字,还有其他解决方案吗?

问题是下面的代码是一个定义,而不是声明:

std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {
   return o << Cplx.m_Real << " i" << Cplx.m_Imaginary;
}

您可以标记上述功能,并使其“内联”,以便多个翻译单位可以定义它:

inline std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {
   return o << Cplx.m_Real << " i" << Cplx.m_Imaginary;
}

或者您可以简单地将函数的原始定义移动到“complex.cpp”源文件。

编译器不会抱怨“real()”,因为它是隐式内联的(任何在类声明中给出其身体的成员函数被解释为已被声明为“inline”)。预处理程序保护措施可以防止您的标头从单个翻译单元(“* .cpp”源文件“)多次包含在内,但两个翻译单元都看到相同的头文件,基本上编译器将”main.cpp“编译为“main.o”(包括由“main.cpp”包含的标题中给出的任何定义),编译器将“complex.cpp”分别编译为“complex.o”(包括由“complex .cpp“),然后链接器将”main.o“和”complex.o“合并成一个二进制文件;在这一点上,链接器为同一个名称的函数找到两个定义,也是在这个指出链接器尝试解析外部引用(例如“main.o”是指“Complex :: Complex”,但没有该函数的定义…链接器定位“complex.o”,并解析那个参考)。

http://stackoverflow.com/questions/2727582/multiple-definition-in-header-file

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:c – 头文件中的多重定义