简体   繁体   English

为什么在头文件中定义类时不会出现多重定义错误?

[英]Why is there no multiple definition error when you define a class in a header file?

I'm not sure if I asked the question correctly, but let me explain.我不确定我问的问题是否正确,但让我解释一下。

First, I read this article that explains the difference between declarations and definitions: http://www.cprogramming.com/declare_vs_define.html首先,我读了这篇文章,解释了声明和定义之间的区别: http : //www.cprogramming.com/declare_vs_define.html

Second, I know from previous research that it is bad practice to define variables and functions in a header file, because during the linking phase you might have multiple definitions for the same name which will throw an error.其次,我从之前的研究中了解到,在头文件中定义变量和函数是不好的做法,因为在链接阶段,您可能有多个相同名称的定义,这会引发错误。

However, how come this doesn't happen for classes?但是,为什么课堂上不会发生这种情况? According to another SO answer ( What is the difference between a definition and a declaration? ), the following would be a class DEFINITION:根据另一个 SO 答案( 定义和声明之间有什么区别? ),以下将是类定义:

    class MyClass {
        private:
        public:
    };

If the above definition is in a header file.如果上面的定义在头文件中。 Then , presumably, you can have multiple .cpp files that #include that header.然后,大概,您可以有多个 .cpp 文件,其中 #include 该标头。 This means the class is defined multiple times after compilation in multiple .o files, but doesn't seem to cause much problems...这意味着在多个 .o 文件中编译后多次定义该类,但似乎不会引起太多问题......

On the other hand, if it was a function being defined in the header file, it would cause problems apparently...from what I understand... maybe?另一方面,如果它是在头文件中定义的函数,它显然会导致问题......据我所知......也许?

So what's so special about class definitions?那么类定义有什么特别之处呢?

The one-definition rule (3.2, [basic.def.odr]) applies differently to classes and functions:单一定义规则(3.2, [basic.def.odr]) 以不同方式应用于类和函数:

1 - No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template. 1 - 任何翻译单元不得包含任何变量、函数、类类型、枚举类型或模板的多个定义。

[...] [...]

4 - Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program [...] 4 - 每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的一个定义 [...]

So while (non-inline) functions may be defined at most once in the whole program (and exactly once if they are called or otherwise odr-used), classes may be defined as many times as you have translation units (source files), but no more than once per translation unit.因此,虽然(非内联)函数在整个程序中最多只能定义一次(如果它们被调用或以其他方式使用 odr 则只能定义一次),类的定义次数可能与翻译单元(源文件)一样多,但每个翻译单元不超过一次。

The reason for this is that since classes are types, their definitions are necessary to be able to share data between translation units.这样做的原因是因为类是类型,它们的定义对于能够在翻译单元之间共享数据是必要的。 Originally, classes ( struct s in C) did not have any data requiring linker support;最初,类(C 中的struct )没有任何需要链接器支持的数据; C++ introduces virtual member functions and virtual inheritance, which require linker support for the vtable , but this is usually worked around by attaching the vtable to (the definition of) a member function. C++ 引入了虚拟成员函数和虚拟继承,这需要vtable 的链接器支持,但这通常通过将 vtable 附加到成员函数(的定义)来解决。

A class definition is just a kind of a blueprint for the objects of that class.类定义只是该类对象的一种蓝图。 It's been the same with struct since the C days.自 C 时代以来, struct一直如此。 No classes or structures actually exists in the code as such.代码中实际上不存在任何类或结构。

Your class definition defines the class, but does not define and objects of that class.您的类定义定义了类,但没有定义该类的对象 It's OK to have the class (or structure) defined in multiple files, because you're just defining a type , not a variable of that type.可以在多个文件中定义类(或结构),因为您只是定义了类型,而不是该类型的变量。 If you just had the definition, no code would be emitted by the compiler.如果您只有定义,则编译器不会发出任何代码。
The compiler actually emits code only after you declare an object (ie variable) of this type:编译器仅在您声明此类型的对象(即变量)后才实际发出代码:

class MyClass myvar;

or:要么:

class MyOtherClass { 
    public: ...
    private: ...
} myvar;         // note the variable name, it instantiates a MyOtherClass

That is what you do NOT want to do in headers because it will cause multiple instances of myvar to be instantiated.这是您不想在标头中执行的操作,因为它会导致实例化myvar 的多个实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM