This post参考单一定义规则。
Wikipedia is pretty bad on explaining how to implement it
我在哪里可以找到关于C ++ .NET中要遵循的指南的好资源?
答案 0 :(得分:6)
一个定义规则基本上意味着变量/函数只能位于已编译可执行文件的地址空间中的一个位置。想到它的一种方法是在编译时,在编译的程序(目标代码)中使用一个内存数组,以及一个引用变量/函数位置的查找表。这是在每个进程级别完成的。假设以下是一个简单的程序:
file1.cpp
int square(int x); // this is a declaration
extern int someVariable; // this is a declration
void square(int x) // this is a definition
{
return x * someVariable;
}
file2.cpp
int square(int x); // this is a declaration
int someVariable; // this is a definition
void main()
{
someVariable = 12;
someVariable = square(4);
}
当编译器开始编译目标代码时,它会读入声明,并将thing放入其表中。在编译file1.cpp结束时,它最终将会出现如下内容:
declarations:
square (XX): function that returns int, and takes a single int as parameter [4 bytes]
someVariable (YY): integer [4 bytes]
data:
12 34 56 78 aa XX XX XX XX ab cd
definition:
square: starts at address 0
这假定函数被编译为那些特定的汇编指令。在链接器时,XX XX XX XX将被someVariable的地址替换。
File2最终结果如下:
declarations:
square (XX): function that returns int, and takes a single int as parameter [4 bytes]
someVariable (YY): integer [4 bytes]
data:
00 00 00 00 12 34 56 78 12 34 56 YY YY YY YY 23 21
definitions:
someVariable: starts at address 0
main: starts at address 4
在这种情况下,YY将被替换为square的地址。
这就是链接器发挥作用的地方。链接器的工作是遍历列表,并在编译时建立一个表,其中包含程序地址空间中的所有内容。但是,如果两个目标文件在尝试链接时具有相同的变量定义,则会出现问题。如果在上面的例子中有someVariable的两个定义,那么它就不知道用什么替换YY。同样,如果 no 定义,则会出现丑陋的链接器错误。
规则的“解决方案”是对文件进行分区,使得您只在.cpp文件中定义,并在.h文件中声明事物,因此上面的示例将变为:
file1.cpp
#include "file2.h"
void square(int x) // this is a definition
{
return x * someVariable;
}
file1.h
int square(int x); // this is a declaration
file2.cpp
#include "file1.h"
int someVariable; // this is a definition
void main()
{
someVariable = 12;
someVariable = square(4);
}
file2.h
extern int someVariable;
请注意,这是一个非常简单的示例,并且它并不真正适用于.NET,因为声明和定义之间没有区别的概念。
答案 1 :(得分:1)
遵守一个定义规则的最简单方法是将定义放在.cpp文件而不是标题中。
人们有时会使用宏和/或预处理器条件将定义放入标题中,以使对象或函数仅在一个编译单元中定义。但是,将定义放在.cpp文件中通常更容易(当然也更容易理解)。