简体   繁体   English

在.h文件或.cpp文件中实现类之间的区别

[英]Difference between implementing a class inside a .h file or in a .cpp file

I was wondering which are the differences between declaring and implementing a class solely in a header file, compared with normal approach in which you protype class in the header and implement in effective .cpp file. 我想知道哪些是仅在头文件中声明和实现类之间的区别,与在标头中对类进行类型化并在有效的.cpp文件中实现的常规方法相比。

To explain better what I'm talking about I mean differences between normal approach: 为了更好地解释我在说什么,我的意思是正常方法之间的区别:

// File class.h
class MyClass 
{
private:
  //attributes
  public:
  void method1(...);
  void method2(...);
  ...
};

//file class.cpp
#include "class.h"

void MyClass::method1(...) 
{
  //implementation
}

void MyClass::method2(...) 
{
  //implementation
}

and a just-header approach: 和一个公正的方法:

// File class.h
class MyClass 
{
private:
  //attributes
public:
  void method1(...) 
  {
      //implementation
  }

  void method2(...) 
  {
    //implementation
  }

  ...
};

I can get the main difference: in the second case the code is included in every other file that needs it generating more instances of the same implementations, so an implicit redundancy; 我可以得到主要区别:在第二种情况下,代码包含在每个需要它生成相同实现的更多实例的其他文件中,因此是隐式冗余; while in the first case code is compiled by itself and then every call referred to object of MyClass are linked to the implementation in class.cpp . 而在第一种情况下,代码是自己编译的,然后每个调用MyClass对象的调用都链接到class.cpp的实现。

But are there other differences? 但还有其他差异吗? Is it more convenient to use an approach instead of another depending on the situation? 取决于具体情况,使用方法而不是另一种方法更方便吗? I've also read somewhere that defining the body of a method directly into a header file is an implicit request to the compiler to inline that method, is it true? 我还读过某个地方,直接将方法的主体定义到头文件中是对编译器内联该方法的隐式请求,是真的吗?

The main practical difference is that if the member function definitions are in the body of the header, then of course they are compiled once for each translation unit which includes that header. 主要的实际区别在于,如果成员函数定义在标题的主体中,那么它们当然会为包含该标题的每个翻译单元编译一次。 When your project contains a few hundred or thousand source files, and the class in question is fairly widely used, this might mean a lot of repetition. 当您的项目包含几百或几千个源文件,并且相关的类被广泛使用时,这可能意味着大量的重复。 Even if each class is only used by 2 or 3 others, the more code in the header, the more work to do. 即使每个类仅由2个或3个其他类使用,标题中的代码越多,工作量就越多。

If the member function definitions are in a translation unit (.cpp file) of their own, then they are compiled once, and only the function declarations are compiled multiple times. 如果成员函数定义在它们自己的转换单元(.cpp文件)中,则它们被编译一次,并且只有函数声明被多次编译。

It's true that member functions defined (not just declared) in the class definition are implicitly inline . 确实,类定义中定义的成员函数(不仅仅是声明的)是隐式inline But inline doesn't mean what people might reasonably guess it means. inline并不意味着人们可能合理地猜测它意味着什么。 inline says that it's legal for multiple definitions of the function to appear in different translation units, and later be linked together. inline表示,函数的多个定义出现在不同的翻译单元中,然后链接在一起是合法的。 This is necessary if the class is in a header file that different source files are going to use, so the language tries to be helpful. 如果类位于不同源文件将要使用的头文件中,则必须执行此操作,因此该语言会尝试提供帮助。

inline is also a hint to the compiler that the function could usefully be inlined, but despite the name, that's optional. inline也是编译器的一个暗示,该函数可以有用地内联,但尽管名称,这是可选的。 The more sophisticated your compiler is, the better it is able to make its own decisions about inlining, and the less need it has for hints. 编译器越复杂,就越能够自己做出关于内联的决定,并且对提示的需求就越少。 More important than the actual inline tag is whether the function is available to the compiler at all. 比实际的内联标记更重要的是该函数是否完全可用于编译器。 If the function is defined in a different translation unit, then it isn't available when the call to it is compiled, and so if anything is going to inline the call then it's going to have to be the linker, not the compiler. 如果函数是在不同的转换单元中定义的,那么在编译对它的调用时它就不可用,因此如果有任何内容要内联调用,则它必须是链接器,而不是编译器。

You might be able to see the differences better by considering a third possible way of doing it: 通过考虑第三种可能的方法,您可能能够更好地看到差异:

// File class.h
class MyClass
{
    private:
        //attributes
    public:
       void method1(...);
       void method2(...);
       ...
};

inline void MyClass::method1(...)
{
     //implementation
}

inline void MyClass::method2(...)
{
     //implementation
}

Now that the implicit inline is out of the way, there remain some differences between this "all header" approach, and the "header plus source" approach. 既然隐式内联已经不在了,那么这个“all header”方法和“header plus source”方法之间仍然存在一些差异。 How you divide your code among translation units has consequences for what happens as it's built. 如何在翻译单元之间划分代码会对构建时发生的事情产生影响。

Any change to a header that includes the implementation will force all other classes that include that header to recompile and relink. 对包含实现的标头的任何更改都将强制包含该标头的所有其他类重新编译和重新链接。

Since headers change less frequently than implementations, by putting the implementation in a separate file, you can save considerable compilation time. 由于标头的更改频率低于实现,因此通过将实现放在单独的文件中,可以节省大量的编译时间。

As some other answers have already pointed out, yes, defining a method within a file's class block will cause the compiler to inline. 正如其他一些答案已经指出的那样,是的,在文件的class块中定义方法将导致编译器内联。

Yes, the compiler will try to inline a method declared directly in header file like: 是的,编译器将尝试内联直接在头文件中声明的方法,如:

class A
{
 public:
   void method()
   {
   }
};

I can think of following conveniences in separating the implementation in header files: 在分离头文件中的实现时,我可以考虑以下方便:

  1. You'll not have code bloat because of the same code getting included in multiple translation units 由于相同的代码包含在多个翻译单元中,因此您不会遇到代码膨胀
  2. Your compilation time will reduce drastically. 您的编译时间将大大减少。 Remember that for any modification in the header file compiler has to build all other files which directly or indirectly include it. 请记住,对于头文件中的任何修改,编译器必须构建直接或间接包含它的所有其他文件。 I guess it will be very frustrating for any one to build the whole binary again just for adding a space in the header file. 我想对于任何人来说再次构建整个二进制文件只是为了在头文件中添加一个空格将是非常令人沮丧的。

Yes, defining methods inside class definition is equivalent to declaring them inline . 是的,在类定义中定义方法相当于将它们inline声明。 There's no other difference. 没有其他区别。 There's no benefit in defining everything in header file. 定义头文件中的所有内容没有任何好处。

Something like that is usually seen in C++ with template classes, since template member definitions have to be included in header file as well (due to the fact that most compilers don't support export ). 类似的东西通常在带有模板类的C ++中看到,因为模板成员定义也必须包含在头文件中(因为大多数编译器不支持export )。 But with ordinary non-template classes there's no point in doing this, unless you really want to declare your methods as inline . 但是对于普通的非模板类,没有必要这样做,除非你真的想要将你的方法声明为inline

For me, the main difference is that a header file is like a "interface" for the class, telling clients of that class what are its public methods (the operations it supports), without the clients worrying about the specific implementation of those. 对我来说,主要区别在于头文件就像是类的“接口”,告诉该类的客户端它的公共方法(它支持的操作)是什么,而客户不担心这些方法的具体实现。 In sense, its a way to encapsulate its clients from implementation changes, because only cpp file changes and hence the compilation time is much less. 从某种意义上说,它是一种从实现更改中封装其客户端的方法,因为只有cpp文件更改,因此编译时间要少得多。

Once in the past I created a module shielding from differences in various CORBA distributions and it was expected to work uniformly on various OS/compiler/CORBA lib combinations. 在过去,我创建了一个模块,可以屏蔽各种CORBA发行版中的差异,并且可以在各种OS /编译器/ CORBA库组合上统一工作。 Making it implemented in a header file made it more easy to add it to a project with a simple include. 在头文件中实现它使得使用简单的include将其添加到项目更加容易。 The same technique guaranteed that the code was recompiled at the same time when the code calling it required recompilation when ie it was being compiled with a different library or on a different OS. 同样的技术保证了代码在调用代码时需要重新编译的同时重新编译,即使用不同的库或不同的OS编译时。

So my point is that if you have a rather tiny library that is expected to be reusable and recompilable across various projects making it a header offers advantages in integration with some other projects as opposed to adding extra files to the main project or recompiling an external lib/obj file. 所以我的观点是,如果你有一个相当小的库,预计可以重复使用并在各种项目中重新编译,使它成为一个标题提供了与其他项目集成的优势,而不是将额外的文件添加到主项目或重新编译外部库/ obj文件。

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

相关问题 .cpp 文件和 .h 文件有什么区别? - What is the difference between a .cpp file and a .h file? pimpl和.cpp文件中的定义类之间的区别 - Difference between pimpl and defining class inside .cpp file 在.h 文件中的 class 中声明 static 变量和在 .cpp 文件中声明“全局”变量有什么区别 - What is the difference between declaring a static variable in a class in the .h file and a “global” variable in the .cpp file .h(头文件)和.cpp文件有什么区别? - What is the difference between a .h(header file) and a .cpp file? 全局const初始化以及.h或.cpp文件中的构造函数之间的差异 - Global const initializing and difference between constructor in .h or .cpp file 将头文件(.h)放在另一个文件(.h 或 .cpp)的开头和结尾的区别 - difference between putting head file(.h) at the beginning and end of another file(.h or .cpp) 包含.cpp文件和.h文件(在cpp中具有相同内容)的区别? - Difference in including the .cpp file and .h file (with the same content in cpp)? c ++中的class(cpp文件和h文件) - class (cpp file & h file) in c++ openssl rc4命令行加密和cpp文件实现rc4的区别 - Difference between openssl rc4 command line encrypt and cpp file implementing rc4 在标头而不是源文件(cpp / h)中声明变量之间有什么区别 - What is the difference between declaring a variable in a header instead of the source file (cpp/h)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM