我正在使用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
你能帮我理解这个错误吗?
答案 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: