对标题和实现文件之间的关系感到困惑

时间:2012-04-18 19:09:42

标签: c++ compilation compiler-errors g++ mingw

我正在使用Code :: Blocks。当我创建一个头文件foo.h并将前向声明以及实现添加到其中时,编译工作正常。创建foo.cpp文件并且不对其进行任何操作仍然有效。但是当我在实现文件中包含头文件但是将实现保留在头文件中时,我收到有关multiple declarations的错误。

我当前项目的示例

// header-file `GKit/math/blendprocs.cpp`
#include "GKit/utils/Color.h"

#ifndef _GKIT_MATH_BLENDPROCS_H_
#define _GKIT_MATH_BLENDPROCS_H_

    namespace GKit {
        namespace math {

            void blendAoverB(GKIT_COLORBLENDPROC_ARGSX) {
                D.a = A.a + (1 - A.a) * B.a;
                D.r = (A.a * A.r + (1 - A.a) * B.a * B.r) / D.a;
                D.g = (A.a * A.g + (1 - A.a) * B.a * B.g) / D.a;
                D.b = (A.a * A.b + (1 - A.a) * B.a * B.b) / D.a;
                GKIT_UTILS_COLOR_NORMALIZE(D);
            }

        }
    }

#endif // _GKIT_MATH_BLENDPROCS_H_

// implementation-file `GKit/math/blendprocs.cpp`
#include "GKit/math/blendprocs.h"

// Compilation output
-------------- Build: Debug in GKit ---------------

Compiling: GKit\math\blendprocs.cpp
Linking console executable: bin_debug\GKit.exe
build_debug\GKit\math\blendprocs.o:C:\Users\niklas\Desktop\GKit/./GKit/math/blendprocs.h:10: multiple definition of `GKit::math::blendAoverB(GKit::utils::Color const&, GKit::utils::Color const&, GKit::utils::Color&)'
build_debug\main.o:C:\Users\niklas\Desktop\GKit/./GKit/math/blendprocs.h:10: first defined here
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
2 errors, 0 warnings

你能帮我理解这个错误吗?

4 个答案:

答案 0 :(得分:1)

在您的标题文件中,您通常只会输入:

// header-file `GKit/math/blendprocs.cpp`
#ifndef _GKIT_MATH_BLENDPROCS_H_
#define _GKIT_MATH_BLENDPROCS_H_

#include "GKit/utils/Color.h"

namespace GKit {
    namespace math {

        void blendAoverB(GKIT_COLORBLENDPROC_ARGSX);

    }
}

#endif // _GKIT_MATH_BLENDPROCS_H_

然后在您的CPP文件中输入实际的实现:

// implementation-file `GKit/math/blendprocs.cpp`
#include "GKit/math/blendprocs.h"

namespace GKit {
    namespace math {

        void blendAoverB(GKIT_COLORBLENDPROC_ARGSX) {
            D.a = A.a + (1 - A.a) * B.a;
            D.r = (A.a * A.r + (1 - A.a) * B.a * B.r) / D.a;
            D.g = (A.a * A.g + (1 - A.a) * B.a * B.g) / D.a;
            D.b = (A.a * A.b + (1 - A.a) * B.a * B.b) / D.a;
            GKIT_UTILS_COLOR_NORMALIZE(D);
        }

    }
}

否则,您的函数的实现将最终出现在包含标头的所有CPP文件中,这会在链接器尝试解析blendAoverB的地址时混淆,因为它可以在所有对象文件中找到它其对应的CPP文件包含带有实现的头文件。

另一方面,最好将包含保护(#ifndef _GKIT_MATH_BLENDPROCS_H_放在标题文件中(除了注释之外)。

答案 1 :(得分:1)

标题中有定义。该定义将在包含该标头的任何源文件中重复;因为在程序中有多个定义通常是错误的,所以构建失败。这被称为一个定义规则,有时被称为ODR。

两个最佳选择是:

  • 将定义移动到源文件中,只在标题中留下声明,或
  • inline添加到定义中;这放松了规则并允许程序中的多个定义,只要它们都相同。

此外,您不应该为包含警卫使用保留名称;您应该从_删除最初的_GKIT_MATH_BLENDPROCS_H_;在任何#include指令之前,最好将这些警卫放在标题的开头。

答案 2 :(得分:1)

您应该内联实现或将实现放在cpp文件中,而不是两者。

// header "GKit/math/blendprocs.h"
#pragma once

#include "GKit/utils/Color.h"

namespace GKit {
        namespace math {
            void blendAoverB(GKIT_COLORBLENDPROC_ARGSX);
        }
    }

// implementation "GKit/math/blendprocs.cpp"
#include "GKit/math/blendprocs.h"

namespace GKit {
        namespace math {

            void blendAoverB(GKIT_COLORBLENDPROC_ARGSX) {
                D.a = A.a + (1 - A.a) * B.a;
                D.r = (A.a * A.r + (1 - A.a) * B.a * B.r) / D.a;
                D.g = (A.a * A.g + (1 - A.a) * B.a * B.g) / D.a;
                D.b = (A.a * A.b + (1 - A.a) * B.a * B.b) / D.a;
                GKIT_UTILS_COLOR_NORMALIZE(D);
            }

        }
    }

或者使用inline关键字在标题中正确内联。

// header "GKit/math/blendprocs.h"
#pragma once

#include "GKit/utils/Color.h"

    namespace GKit {
        namespace math {
            inline void blendAoverB(GKIT_COLORBLENDPROC_ARGSX) {
                D.a = A.a + (1 - A.a) * B.a;
                D.r = (A.a * A.r + (1 - A.a) * B.a * B.r) / D.a;
                D.g = (A.a * A.g + (1 - A.a) * B.a * B.g) / D.a;
                D.b = (A.a * A.b + (1 - A.a) * B.a * B.b) / D.a;
                GKIT_UTILS_COLOR_NORMALIZE(D);
            }
        }
    }

答案 3 :(得分:0)

这正是消息所说的。您应该熟悉Inline和ODR。你无法对ODR进行多重定义。我猜你的blendprocs.cpp在不同的编译单元中被包含多次。它与Why aren't my compile guards preventing multiple definition inclusions?

有关

ODR:

http://en.wikipedia.org/wiki/One_Definition_Rule