Programing

헤더 파일의 여러 클래스 vs. 클래스 당 단일 헤더 파일

lottogame 2020. 11. 7. 08:53
반응형

헤더 파일의 여러 클래스 vs. 클래스 당 단일 헤더 파일


어떤 이유로 든 우리 회사에는 다음과 같은 코딩 지침이 있습니다.

Each class shall have it's own header and implementation file.

따라서 우리가라는 클래스를 작성했다면 MyString관련된 MyStringh.hMyString.cxx 가 필요합니다 .

다른 사람이 이것을합니까? 결과적으로 컴파일 성능에 미치는 영향을 본 사람이 있습니까? 10000 개 파일의 5000 개 클래스가 2500 개 파일의 5000 개 클래스만큼 빠르게 컴파일됩니까? 그렇지 않다면 차이가 눈에 띄나요?

[우리는 C ++를 코딩하고 일상적인 컴파일러로 GCC 3.4.4를 사용합니다.]


여기서 용어는 번역 단위 이며, 가능한 경우 번역 단위당 하나의 클래스, 즉 .cpp 파일 당 하나의 클래스 구현과 동일한 이름의 해당 .h 파일을 갖고 싶습니다.

일반적으로 (컴파일 / 링크에서) 이런 방식으로 작업하는 것이 더 효율적입니다. 특히 증분 링크 등을 수행하는 경우 더욱 그렇습니다. 아이디어는 하나의 번역 단위가 변경 될 때 많은 추상화를 단일 번역 단위로 묶기 시작했을 때해야하는 것처럼 많은 것을 다시 빌드 할 필요가 없도록 번역 단위가 격리된다는 것입니다.

또한 파일 이름 ( "Error in Myclass.cpp, line 22")을 통해 많은 오류 / 진단이보고되며 파일과 클래스간에 일대일 대응이있는 경우 도움이됩니다. (또는 2 대 1 서신이라고 부를 수 있다고 가정합니다).


수천 줄의 코드에 압도됩니까?

디렉토리에서 클래스 당 하나의 헤더 / 소스 파일 세트를 갖는 것은 지나친 것처럼 보일 수 있습니다. 그리고 수업 수가 100 개나 1000 개에 가까워지면 무섭기도합니다.

그러나 "모든 것을 모으자"라는 철학에 따라 소스를 가지고 놀아 본 결과, 결론은 파일을 작성한 사람 만이 내부에서 잃어 버리지 않을 희망이 있다는 것입니다. IDE를 사용하더라도 20,000 줄의 소스로 플레이 할 때 문제와 정확히 관련이없는 것은 마음을 닫기 때문에 놓치기 쉽습니다 .

실제 예 : 수천 줄의 소스에 정의 된 클래스 계층 구조가 다이아몬드 상속으로 폐쇄되었고 일부 메서드는 정확히 동일한 코드를 가진 메서드에 의해 자식 클래스에서 재정의되었습니다. 이것은 쉽게 간과되고 (2 만 줄의 소스 코드를 탐색 / 확인하고 싶습니까?) 원래 방법이 변경되었을 때 (버그 수정) 그 효과는 예외적 인 것만 큼 보편적이지 않았습니다.

의존성이 순환 되는가?

템플릿 코드에서이 문제가 있었지만 일반 C ++ 및 C 코드에서도 비슷한 문제가 발생했습니다.

소스를 구조체 / 클래스 당 1 개의 헤더로 나누면 다음을 수행 할 수 있습니다.

  • 전체 객체를 포함하는 대신 기호 포워드 선언을 사용할 수 있으므로 컴파일 속도가 빨라집니다.
  • 클래스간에 순환 종속성이 있습니다 (§) (즉, 클래스 A에는 B에 대한 포인터가 있고 B에는 A에 대한 포인터가 있음)

소스 제어 코드에서 클래스 종속성은 헤더를 컴파일하기 위해 파일에서 클래스를 정기적으로 위아래로 이동할 수 있습니다. 다른 버전에서 동일한 파일을 비교할 때 그러한 움직임의 진화를 연구하고 싶지 않습니다.

별도의 헤더를 사용하면 코드가 더 모듈화되고 컴파일 속도가 빨라지며 다른 버전 diff를 통해 진화를 더 쉽게 연구 할 수 있습니다.

템플릿 프로그램의 경우 헤더를 템플릿 클래스 선언 / 정의를 포함하는 .HPP 파일과 해당 클래스 메서드의 정의를 포함하는 .INL 파일의 두 파일로 분할해야했습니다.

이 모든 코드를 하나의 고유 한 헤더에만 넣는 것은이 파일의 시작 부분에 클래스 정의를 넣고 끝에 메서드 정의를 넣는 것을 의미합니다.

그리고 누군가가 단일 헤더 전용 솔루션을 사용하여 코드의 작은 부분 만 필요로하더라도 여전히 느린 컴파일 비용을 지불해야합니다.

(§) 어떤 클래스가 어떤 클래스를 소유하고 있는지 아는 경우 클래스간에 순환 종속성이있을 수 있습니다. 이것은 shared_ptr 순환 종속성 반 패턴이 아닌 다른 클래스의 존재를 알고있는 클래스에 대한 토론입니다.

마지막 한마디 : 헤더는 자급 자족해야합니다.

그러나 한 가지는 여러 헤더와 여러 소스의 솔루션으로 존중되어야합니다.

하나의 헤더를 포함하면 어떤 헤더 든 소스가 깔끔하게 컴파일되어야합니다.

각 헤더는 자급 자족해야합니다. 하나의 열거 형으로 인해 포함해야하는 1,000 줄 헤더의 기호를 정의하는 헤더를 찾기 위해 10,000 개 이상의 소스 파일 프로젝트를 검색하여 보물 찾기가 아니라 코드를 개발해야합니다 .

즉, 각 헤더가 사용하는 모든 기호를 정의 또는 전달 선언하거나 필요한 모든 헤더 (및 필요한 헤더 만)를 포함합니다.

순환 종속성에 대한 질문

underscore-d 가 묻습니다.

별도의 헤더를 사용하면 순환 종속성에 어떤 차이가 있는지 설명 할 수 있습니까? 나는 그렇게 생각하지 않는다. 두 클래스가 모두 동일한 헤더에서 완전히 선언 된 경우에도 단순히 하나의 핸들을 다른 하나에 대한 핸들을 선언하기 전에 미리 정방향 선언하여 간단하게 순환 종속성을 만들 수 있습니다. 다른 모든 것은 좋은 점처럼 보이지만, 별도의 헤더가 순환 종속성을 용이하게한다는 생각은 엉망인 것 같습니다.

underscore_d, 11 월 13 일 23:20

두 개의 클래스 템플릿 A와 B가 있다고 가정 해 보겠습니다.

클래스 A (각각 B)의 정의에 B (각각 A)에 대한 포인터가 있다고 가정 해 보겠습니다. 클래스 A (각각 B)의 메소드가 실제로 B (각각 A)의 메소드를 호출한다고 가정 해 봅시다.

클래스 정의와 해당 메서드 구현 모두에 순환 종속성이 있습니다.

A와 B가 일반 클래스이고 A와 B의 메서드가 .CPP 파일에 있으면 문제가 없습니다. 순방향 선언을 사용하고 각 클래스 정의에 대한 헤더가 있으면 각 CPP에 두 HPP가 모두 포함됩니다.

그러나 템플릿이 있으므로 실제로 위의 패턴을 재현해야하지만 헤더 만 사용합니다.

이것은 다음을 의미합니다.

  1. 정의 헤더 A.def.hpp 및 B.def.hpp
  2. 구현 헤더 A.inl.hpp 및 B.inl.hpp
  3. 편의상 "순진한"헤더 A.hpp 및 B.hpp

각 헤더에는 다음과 같은 특성이 있습니다.

  1. A.def.hpp (resp. B.def.hpp)에는 클래스 B (resp. A)의 포워드 선언이있어 해당 클래스에 대한 포인터 / 참조를 선언 할 수 있습니다.
  2. A.inl.hpp (각각 B.inl.hpp)에는 A.def.hpp 및 B.def.hpp가 모두 포함되어 A (각각 B)의 메서드가 클래스 B (각각 A)를 사용할 수있게합니다. .
  3. A.hpp (각각 B.hpp)는 A.def.hpp 및 A.inl.hpp (각각 B.def.hpp 및 B.inl.hpp)를 모두 직접 포함합니다.
  4. 물론 모든 헤더는 자체적으로 충분해야하며 헤더 가드로 보호되어야합니다.

순진한 사용자는 A.hpp 및 / 또는 B.hpp를 포함하므로 전체 혼란을 무시합니다.

그리고 그 구성이 있다는 것은 라이브러리 작성자가 A와 B 사이의 순환 종속성을 해결하는 동시에 두 클래스를 별도의 파일로 유지하여 일단 스키마를 이해하면 쉽게 탐색 할 수 있음을 의미합니다.

가장자리 케이스 (서로 알고있는 두 개의 템플릿)였습니다. 대부분의 코드 에는 그 트릭이 필요 하지 않을 것으로 예상 됩니다.


우리는 직장에서 그렇게합니다. 클래스와 파일의 이름이 같으면 물건을 찾기가 더 쉽습니다. 성능에 관해서는 단일 프로젝트에 5000 개의 클래스가 있어서는 안됩니다. 그렇게하면 일부 리팩토링이 순서대로 진행될 수 있습니다.

That said, there are instances when we have multiple classes in one file. And that is when it's just a private helper class for the main class of the file.


In addition to simply being "clearer", separating classes into separate files makes it easier for multiple developers not to step on each others toes. There will be less merging when it comes time to commit changes to your version control tool.


+1 for separation. I just came onto a project where some classes are in files with a different name, or lumped in with another class, and it is impossible to find these in a quick and efficient manner. You can throw more resources at a build - you can't make up lost programmer time because (s)he can't find the right file to edit.


Most places where I have worked have folowed this practice. I've actually written coding standards for BAE (Aust.) along with the reasons why instead of just carving something in stone with no real justification.

Concerning your question about source files, it's not so much time to compile but more an issue of being able to find the relevant code snippet in the first place. Not everyone is using an IDE. And knowing that you just look for MyClass.h and MyClass.cpp really saves time compared to running "grep MyClass *.(h|cpp)" over a bunch of files and then filtering out the #include MyClass.h statements...

Mind you there are work-arounds for the impact of large numbers of source files on compile times. See Large Scale C++ Software Design by John Lakos for an interesting discussion.

You might also like to read Code Complete by Steve McConnell for an excellent chapter on coding guidelines. Actualy, this book is a great read that I keep coming back to regularly


It's common practice to do this, especially to be able to include .h in the files that need it. Of course the performance is affected but try not to think about this problem until it arises :).
It's better to start with the files separated and after that try to merge the .h's that are commonly used together to improve performance if you really need to. It all comes down to dependencies between files and this is very specific to each project.


The best practice, as others have said, is to place each class in its own translation unit from a code maintenance and understandability perspective. However on large scale systems this is sometimes not advisable - see the section entitled "Make Those Source Files Bigger" in this article by Bruce Dawson for a discussion of the tradeoffs.


I found these guidelines particularly useful when it comes to header files : http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Header_Files


It is very helpful to have only have one class per file, but if you do your building via bulkbuild files which include all the individual C++ files, it makes for faster compilations since startup time is relatively large for many compilers.


I'm surprised that almost everyone is in favor of having one file per class. The problem with that is that in the age of 'refactoring' one may have a hard time keeping the file and class names in synch. Everytime you change a class name, you then have to change the file name too, which means that you have to also make a change everywhere the file is included.

I personally group related classes into a single files and then give such a file a meaningful name that won't have to change even if a class name changes. Having fewer files also makes scrolling through a file tree easier. I use Visual Studio on Windows and Eclipse CDT on Linux, and both have shortcut keys that take you straight to a class declaration, so finding a class declaration is easy and quick.

Having said that, I think once a project is completed, or its structure has 'solidified', and name changes become rare, it may make sense to have one class per file. I wish there was a tool that could extract classes and place them in distinct .h and .cpp files. But I don't see this as essential.

The choice also depends on the type of project one works on. In my opinion the issue doesn't deserve a black and white answer since either choice has pros and cons.


The same rule applies here, but it notes a few exceptions where it is allowed Like so:

  • Inheritance trees
  • Classes that are only used within a very limited scope
  • Some Utilities are simply placed in a general 'utils.h'

Two words: Ockham's Razor. Keep one class per file with the corresponding header in a separate file. If you do otherwise, like keeping a piece of functionality per file, then you have to create all kinds of rules about what constitutes a piece of functionality. There is much more to gain by keeping one class per file. And, even half decent tools can handle large quantities of files. Keep it simple my friend.

참고URL : https://stackoverflow.com/questions/28160/multiple-classes-in-a-header-file-vs-a-single-header-file-per-class

반응형