代码之家  ›  专栏  ›  技术社区  ›  Jérôme

头文件中有多个定义

  •  28
  • Jérôme  · 技术社区  · 14 年前

    给定此代码示例:

    复杂h:

    #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
    

    #include "complex.h"
    
    Complex::Complex(float Real, float Imaginary) {
       m_Real = Real;
       m_Imaginary = Imaginary;
    }
    

    主.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&)
    

    inline 解决了问题,但我不明白为什么。为什么编译器会抱怨多重定义?我的头文件受到保护(使用 #define COMPLEX_H ).

    如果你抱怨 operator<< public real()

    除了使用

    4 回复  |  直到 11 年前
        1
  •  63
  •   Michael Aaron Safyan    14 年前

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

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

    您可以将上面的函数标记为“inline”,以便多个翻译单元可以定义它:

    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”中定位定义,并解析该引用)。

        2
  •  5
  •   XAder    14 年前

    将实现移到complex.cpp

    现在,在包含此文件之后,正在将实现编译到每个文件。 稍后在链接过程中,由于重复的实现,会出现明显的冲突。

    ::real()未报告,因为它是隐式内联的(类定义内的实现)

        3
  •  1
  •   Paul Wintz    7 年前

    我有这个问题,即使在我的源和头文件是正确的。

    要修复,请使用 Project > Clean 然后重建。

        4
  •  0
  •   thayne    4 年前

    定义 inline 定义为 static . 这也将避免多重定义错误。