0

我正在使用 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

4 回答 4

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_放在头文件中的其他任何内容之前(可能用于注释除外)。

于 2012-04-18T19:15:57.000 回答
1

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

两个最佳选择是:

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

此外,您不应该为包含防护使用保留名称;您应该__GKIT_MATH_BLENDPROCS_H_;中删除首字母 最好将这些守卫放在标题的开头,在任何#include指令之前。

于 2012-04-18T19:16:27.273 回答
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);
            }
        }
    }
于 2012-04-18T19:16:29.477 回答
0

这正是消息所说的。您应该熟悉内联和 ODR。你不能有多个定义,它是针对 ODR 的。我猜你的 blendprocs.cpp 不止一次包含在不同的编译单元中。它与为什么我的编译防护不能防止多个定义包含有关?

网上争议解决:

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

于 2012-04-18T19:16:33.967 回答