multiple definition in header file

无人久伴 提交于 2019-11-26 22:08:22

The problem is that the following piece of code is a definition, not a declaration:

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

You can either mark the function above and make it "inline" so that multiple translation units may define it:

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

Or you can simply move the original definition of the function to the "complex.cpp" source file.

The compiler does not complain about "real()" because it is implicitly inlined (any member function whose body is given in the class declaration is interpreted as if it had been declared "inline"). The preprocessor guards prevent your header from being included more than once from a single translation unit ("*.cpp" source file"). However, both translation units see the same header file. Basically, the compiler compiles "main.cpp" to "main.o" (including any definitions given in the headers included by "main.cpp"), and the compiler separately compiles "complex.cpp" to "complex.o" (including any definitions given in the headers included by "complex.cpp"). Then the linker merges "main.o" and "complex.o" into a single binary file; it is at this point that the linker finds two definitions for a function of the same name. It is also at this point that the linker attempts to resolve external references (e.g. "main.o" refers to "Complex::Complex" but does not have a definition for that function... the linker locates the definition from "complex.o", and resolves that reference).

And is there another solution as using the inline keyword?

Yes, there is. Apart form defining the method inside the implementation file complex.cpp as mentioned by others, you can also put the definition into a nameless namespace.

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

In practice, this will create a unique namespace for each compilation unit. That way, you prevent the name clashes. However, the names are still exported from the compilation unit but useless (since the names are unknown).

Putting the definition inside the implementation file is often a better solution. However, for class templates you can’t do that since C++ compilers don’t support instantiating templates in a compilation unit different from the one they were defined in. In those case, you have to use either inline or an unnamed namespace.

Move implementation to complex.cpp

Right now after including this file implementation is being compiled to every file. Later during linking there's a obvious conflict because of duplicate implementations.

::real() is not reported because it's inline implicitly (implementation inside class definition)

I was having this problem, even after my source and header file were correct.

It turned out Eclipse was using stale artifacts from a previous (failed) build.

To fix, use Project > Clean then rebuild.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!