让我有两个 cpp 文件:
//--a.cpp--//
class A
{
public:
void bar()
{
printf("class A");
}
};
//--b.cpp--//
class A
{
public:
void bar()
{
printf("class A");
}
};
当我编译并将这些文件链接在一起时,我没有发现任何错误。但如果我写下以下内容:
//--a.cpp--//
int a;
//--b.cpp--//
int a;
在编译和链接这些资源后,我遇到了一个错误,因为 a
的重新定义。但是对于我已经重新定义的类,没有出现错误。我很困惑。
类是类型。大多数情况下,它们是编译时工件;另一方面,全局变量是运行时工件。
在您的第一个示例中,每个翻译单元都有自己的 class a
定义。由于翻译单元彼此分离,并且它们不会生成具有相同名称的全局运行时工件,所以这是可以的。该标准要求每个翻译单元只有一个类定义 - 请参阅第 3.2.1 和 3.2.4 节:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.
Exactly one definition of a class is required in a translation unit if the class is used in a way that requires the class type to be complete.
但是,该标准允许在单独的翻译单元中定义多个类 - 请参阅第 3.2.6 节:
There can be more than one definition of a class type, enumeration type, inline function with external linkage, class template, non-static function template, static data member of a class template, member function of a class template, or template specialization for
which some template parameters are not specified in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. [...]
接下来是一长串要求,归结起来就是两个类定义需要相同;否则,程序被认为是病式的。
在您的第二个示例中,您在两个翻译单元中定义了一个全局运行时工件(变量 int a
)。当链接器尝试生成最终输出(可执行文件或库)时,它会发现这两者,并发出重新定义错误。请注意,上述规则 3.2.6 不包括具有外部链接的变量。
如果您将变量声明为static
,您的程序将会编译,因为静态变量对于定义它们的翻译单元而言是本地的。
虽然两个程序都可以编译,但它们编译的原因不同:在多个类定义的情况下,编译器假定这两个类是相同的;在第二种情况下,编译器认为这两个变量相互独立。