8

필자는 자신의 코드를 정리하는 것을 좋아하는데 이상적으로 파일 당 하나의 클래스가 필요하거나 비 멤버 함수가있을 때 파일 당 하나의 함수가 필요합니다.많은 기능을 하나의 파일에 넣어야합니까? 또는 파일 당 하나의 기능이 다소 차이가 있습니까?

이유는 다음과 같습니다

  1. 내가이 특정 함수 또는 클래스를 찾을해야하는 파일에 난 항상 알 수 코드를 읽을 때. 그 다음 하나의 클래스 또는 1 비회원 헤더 파일 당 기능의 경우

  2. 나는 전체적으로 엉망 내가 include 헤더 파일을 포함하지 않습니다.

  3. 함수에서 작은 변경을하면 해당 함수 만 다시 컴파일해야합니다.

그러나 많은 헤더와 많은 구현 파일로 모든 것을 분할하면 컴파일 속도가 느려질 수 있습니다. 내 프로젝트에서, 대부분의 함수는 특정 수의 템플리트 된 다른 라이브러리 함수에 액세스합니다. 이 코드는 각 구현 파일에 대해 한 번씩 반복해서 컴파일됩니다. 내 전체 프로젝트를 컴파일하는 데 현재 한 대의 컴퓨터에서 45 분 정도 걸립니다. 오브젝트 파일은 약 50 개이며, 각각은 비싸기 쉬운 컴파일 헤더를 사용합니다.

어쩌면, 그것은 헤더 파일 당 하나 개의 클래스 (또는 비 멤버 함수)를 가지고 있지만, 다음 예에서와 같이, 하나 구현 파일에 많은 또는 모든 기능의 구현을 성공시키는 허용? 다시

// foo.h 
void foo(int n); 

// bar.h 
void bar(double d); 

// foobar.cpp 
#include <vector> 
void foo(int n) { std::vector<int> v; ... } 
void bar(double d) { std::vector<int> w; ... } 

은 장점이다 (나는 foobar.cpp하나 파일이기 때문에 빠를 것이다 전체 프로젝트의 바로 foo는 함수 또는 바로 바 기능, 컴파일을 포함 할 수있을 때문에 std::vector<int> 것 다른 비싼 컴파일 템플리트에 대한 예제는 여기에서 단 한번 컴파일해야합니다. foo.cppbar.cpp을 따로 컴파일해야합니다. 물론 위의 이유 (3)은이 시나리오에서는 유효하지 않습니다. 단지 foo() {...}를 변경 한 후에 잠재적으로 큰 파일 foobar.cpp 전체를 다시 컴파일해야합니다.

귀하의 의견이 궁금합니다.

+3

는 하하, 당신은 호주있어 간단하게하기 위해 여기를 엉망으로! 미국 영어에서는 "좋아"하지 않지만 "사랑합니다". 또한 상황은 대개 "선"또는 "위대한"대신에 "우수"하고 "엄청납니다"! 미국 영어로, 당신이 단지 "무언가를"좋아한다고 말한다면, 당신이 실제로 그것을 좋아하지 않는다는 것을 의미합니다! ;-) – Frank

+1

... "우수"의견에 감사드립니다! :-P – Frank

답변

8

IMHO, 항목을 논리적 그룹으로 결합하고 이에 따라 파일을 만들어야합니다.

필자가 함수를 쓰고있을 때 서로가 긴밀하게 관련되어있는 경우가 종종 있습니다. 나는 그것들을 하나의 헤더와 구현 파일에 넣는 경향이있다.

클래스를 작성할 때 일반적으로 헤더 및 구현 파일 당 하나의 중량 클래스로 제한됩니다. 일부 편의 기능이나 작은 도우미 클래스를 추가 할 수 있습니다.

구현 파일이 수천 줄의 길이라는 것을 알게되면 대개 그곳에 너무 많아서 해체해야한다는 신호입니다.

7

파일 당 하나의 기능이 제 생각에는 지저분해질 수 있습니다. POSIX와 ANSI C 헤더가 같은 방법으로 만들어 졌는지 상상해보십시오.

#include <strlen.h> 
#include <strcpy.h> 
#include <strncpy.h> 
#include <strchr.h> 
#include <strstr.h> 
#include <malloc.h> 
#include <calloc.h> 
#include <free.h> 
#include <printf.h> 
#include <fprintf.h> 
#include <vpritnf.h> 
#include <snprintf.h> 

파일 당 하나의 클래스가 좋습니다.

+2

나에게는 꽤 좋은 소리인데, 다시 한번 어떤 헤더가 어떤 함수인지를 조사해야하지만, string.h에있는 모든 문자열 함수를 포함하는 편의 헤더를 가질 수도 있습니다. 반면 컴파일러는 strlen이 사용되는 경우 "strlen.h"를 포함하는 것에 대한 가정을 할 수 있습니다. (물론 경고와 함께) – technosaurus

1

정적 메서드 하나 이상의 클래스로 다시 정의 할 수 있습니다. 이렇게하면 여러 소스를 하나의 소스 파일로 그룹화 할 수있는 좋은 기회가됩니다.

소스 파일이 오브젝트 파일과 일대일로 연결되어 있고 링커가 전체 오브젝트 파일을 링크하는 경우 하나의 소스 파일에 여러 기능이 있거나없는 여러 가지 이유가 있습니다. 다른 하나는 별도의 소스 파일에 넣으므로 (링커가 다른 링커없이 연결할 수 있도록).

+0

클래스의 정적 멤버가 네임 스페이스에 함수를 추가하는 것이 좋습니다. 함수를 사용하는 구문은 동일하지만 의도를보다 명확하게 나타냅니다. – KeithB

+0

대부분의 링커는 최종 실행 파일에서 호출 된 함수 만 가져 오므로 링커를 최적화하는 것이 합리적이라고 생각하지 않습니다. – KeithB

1

파일 당 함수에서 파일을 분할하려고했지만 몇 가지 단점이 있습니다. 때로는 코드를 리팩토링하지 않는 한 함수가 필요할 때보 다 더 커지는 경향이 있습니다 (매번 새로운 C 파일을 추가하고 싶지는 않습니다). 현재 나는 1 ~ 3 개의 함수를 c 파일에 넣고 모든 c 파일은 디렉토리에있는 기능을 그룹화합니다. headerfiles 들어, 나는 모든 기능을 필요할 때 즉시 포함 할 수 있도록 Funcionality.hSubfunctionality.h 있습니다 전체 패키지가 필요하지 않은 경우 작은 유틸리티 기능.

1

내 옛 프로그래밍 교수는 유지 보수를 위해 수백 줄의 코드마다 모듈을 분리 할 것을 제안했습니다. C++에서는 더 이상 개발하지 않지만 C#에서는 파일 당 하나의 클래스로 제한되며 파일의 크기는 내 개체와 관련이없는 한 중요하지 않습니다. #pragma regions를 사용하여 편집기 공간을 효율적으로 줄일 수 있습니다. C++ 컴파일러에 포함되어 있는지 확실하지 않지만, 확실히 사용할 수는 있습니다.

저는 여전히 C++로 프로그래밍 중이 었는데 파일 당 여러 기능을 사용하여 기능을 그룹화했습니다. 그래서 나는 그 "서비스"를 정의하는 몇 가지 기능을 가진 'Service.cpp'라는 파일을 가질 수 있습니다. 파일 하나당 하나의 기능을 갖게되면 후회로 인해 어떻게 든 프로젝트로 돌아갈 수 있습니다.

파일 당 수천 줄의 코드를 갖는 것이 필요하지는 않습니다. 함수 자체는 최대로 수백 줄 이상의 코드가 될 수 없습니다. 함수는 한 가지 일을하고 최소한으로 유지해야한다는 것을 항상 기억하십시오. 함수가 두 가지 이상을 수행하면 헬퍼 메소드로 리팩터링되어야합니다.

단일 엔티티 중 하나를 정의하는 여러 소스 파일을 가질 수도 있습니다. 즉 : 'ServiceConnection.cpp' 'ServiceSettings.cpp'등등.

때때로 하나의 개체를 만들고 다른 개체를 소유하고 있으면 여러 클래스를 하나의 파일로 결합합니다. 예를 들어 'ButtonLink'객체가 포함 된 버튼 컨트롤을 Button 클래스에 결합 할 수 있습니다. 때로는 그렇지 않지만, 그 순간의 "환경 설정"결정입니다.

가장 적합한 방법을 선택하십시오. 소규모 프로젝트에서 다양한 스타일로 실험 해보십시오. 희망이 당신을 조금 도와줍니다.

1

HEADER 부분의 경우 항목을 논리적 그룹으로 결합하고이를 기반으로 HEADER 파일을 만들어야합니다. 이것은 매우 논리적 인 것처럼 보입니다.

SOURCE 부분의 경우 각 기능 구현을 별도의 SOURCE 파일에 넣어야합니다. (정적 함수는이 경우 예외입니다.) 처음에는 논리적으로 보이지 않지만 컴파일러는 함수에 대해 알고 있지만 링커는 o/obj 파일과 해당 내 보낸 심볼에 대해서만 알고 있습니다.이것은 출력 파일의 크기를 상당히 바꿀 수 있으며 이는 임베디드 시스템에서 매우 중요한 문제입니다. 나는 당신의 접근 방식에 몇 가지 장점을 볼 수 있지만 몇 가지 단점이있다

+0

하, 나는 그 반대도 마찬가지라고 생각했다. HEADER 파일에 많은 함수를 넣을 이유가 없다. 컴파일 의존성이 생기기 때문이다. 하지만 많은 함수 구현을 SOURCE에 넣는 것은 나에게 의미가있다. – Frank

+0

Visual C++ crt 소스 코드 또는 glibc를 조사하면된다. – Malkocoglu

1

체크 아웃의 glibc 또는 Visual C++ CRT 소스 트리 ....

1) 패키지를 포함하면 악몽입니다. 필요한 기능을 얻으려면 10-20 개까지 포함될 수 있습니다. STDIO 또는 StdLib가 이런 식으로 구현 된 경우 이미지 예를 들어.

2) 코드를 탐색하는 것은 일반적으로 파일을 전환하는 것보다 파일을 스크롤하는 것이 더 쉽기 때문에 약간의 어려움이있을 것입니다. 분명히 너무 큰 파일은 어렵지만, 심지어는 현대 IDE를 사용하여 파일을 원하는대로 축소 할 수 있으며 많은 기능 단축 목록이 있습니다.

3) 파일 유지 관리가 쉽지 않습니다.

4) 저는 작은 기능과 리펙토링에 대한 엄청난 팬입니다. 오버 헤드 (새 파일 만들기, 소스 컨트롤에 추가 ...)를 추가하면 사람들이 1 기능을 3 부분으로 나누는 대신 하나의 큰 기능을 만드는보다 긴 기능을 작성하도록 권장합니다.

+0

Re : # 4 : 아마도 파일 당 하나의 "공용"기능으로 자신을 제한 할 수 있으며 필요한만큼 그 파일에 많은 정적 기능을 포함 할 수 있습니다. 그렇게하면, 코드를 사용하고 함수를 찾으려면, 어디에서 봐야할지 정확히 알 수 있습니다. 또한 "이 파일의 모든 것이 관련되어 /이 단일 기능으로"라는 개념을 유지합니다. – Ethan

2

파일 당 하나의 외부 함수 원칙을 사용합니다. 그러나이 파일에는 해당 함수를 구현하는 데 사용되는 이름없는 네임 스페이스에 여러 가지 "도우미"함수가있을 수 있습니다.

우리의 경험에서, 다른 의견과는 달리 이것은 두 가지 주요 이점을 가지고 있습니다. 첫 번째는 특정 API가 수정 될 때 모듈을 다시 빌드해야하기 때문에 빌드 시간이 빠릅니다.

// getShapeColor.h 
Color getShapeColor (Shape); 

// getTextColor.h 
Color getTextColor (Text); 

나는 표준 라이브러리에 대한 좋은 예이다 것을 동의 : 두 번째 장점은 공통 이름 지정 체계를 사용하여, 당신이 호출 할 함수를 포함하는 헤더를 검색하는 시간을 보낼 필요가 결코 없다는 것입니다 파일 당 하나의 (외부) 기능을 사용하지 마십시오. 표준 라이브러리는 절대로 변경되지 않고 잘 정의 된 인터페이스를 가지고 있으므로 위의 사항 중 어느 것도 해당 라이브러리에 적용되지 않습니다.

즉, 표준 라이브러리의 경우에도 개별 기능을 분리 할 때 잠재적 인 이점이 있습니다. 첫 번째는 안전하지 않은 버전의 함수가 사용될 때 컴파일러가 유용한 경고를 생성 할 수 있다는 것입니다. strcpy vs strncpy과 비슷한 방식으로 g ++에서 vs 포함 여부를 경고하는 데 사용됩니다. 내가 memmove를를 사용하고자 할 때

또 다른 장점은 내가 더 이상 메모리을 포함하여 간파되지 않을 것입니다!

0

정적 라이브러리를 만드는 경우 파일 당 하나의 기능이 기술적 이점을 갖습니다 (이는 Musl-libc 프로젝트가이 패턴을 따르는 이유 중 하나라고 생각합니다).

정적 라이브러리는 객체 파일 단위로 연결되어 당신이 *로 구성된 정적 라이브러리 libfoobar.a있는 경우에 이렇게 : 당신이 bar 기능에 대한 LIB를 연결하면 다음

foo.o 
    foo1 
    foo2 
bar.o 
    bar 

을의 bar.o 아카이브 멤버 얻을 것이다 연결된 회원은 foo.o 회원이 아닙니다.foo1으로 연결하면 foo.o 회원이 연결되어 불필요한 foo2 기능을 가져옵니다.

불필요한 기능이 (-ffunction-sections -fdata-sections--gc-sections)에 링크되는 것을 방지하는 다른 방법이 있지만 파일 당 하나의 기능이 가장 안정적 일 수 있습니다.


  • 나는 C++를 무시하고있어 이름은