C ++에서 인터페이스 및 구현을 구성하는 방법


12

헤더 파일에 무엇이 들어가고 cpp 파일에 무엇이 들어가는 지에 관해 C ++에는 여러 가지 패러다임이 있음을 보았습니다. AFAIK, 대부분의 사람들, 특히 C 배경의 사람들은 다음을 수행합니다.

foo.h

 class foo {
 private:
     int mem;
     int bar();
 public:
     foo();
     foo(const foo&);
     foo& operator=(foo);
     ~foo();
 }

foo.cpp

 #include foo.h
 foo::bar() { return mem; }
 foo::foo() { mem = 42; }
 foo::foo(const foo& f) { mem = f.mem; }
 foo::operator=(foo f) { mem = f.mem; }
 foo::~foo() {}
 int main(int argc, char *argv[]) { foo f; }

그러나 내 강사는 일반적으로 다음과 같은 초보자에게 C ++을 가르칩니다.

foo.h

 class foo {
 private:
     int mem;
     int bar() { return mem; }
 public:
     foo() { mem = 42; }
     foo(const foo& f) { mem = f.mem; }
     foo& operator=(foo f) { mem = f.mem; }
     ~foo() {}
 }

foo.cpp

 #include foo.h
 int main(int argc, char* argv[]) { foo f; }
 // other global helper functions, DLL exports, and whatnot

원래 Java에서 왔을 때 인터페이스 나 메소드 이름이 변경되면 클래스에서 다른 항목 들여 쓰기를 좋아한다는 것만으로 한 곳에서 무언가를 변경해야한다는 것과 같은 여러 가지 이유로 항상 두 번째 방법을 고수했습니다. 구현을 살펴보면에 foo비해 이름이 더 읽기 쉽습니다 foo::foo.

어느 쪽이든 찬반 양론을 수집하고 싶습니다. 어쩌면 다른 방법이 있습니까?

내 방식의 한 가지 단점은 물론 때때로 사전 선언이 필요하다는 것입니다.


2
foo.cpp이제는 foo수업과 관련이 없으며 비워 두어야합니다 (아마도 #include빌드 시스템을 행복하게 만들 수 있습니다).
벤자민 Bannier

2
강사가 미쳤어.
궤도에서 가벼움 레이스

답변:


16

두 번째 버전은 작성하기 쉽지만 구현과 인터페이스를 혼합하고 있습니다.

헤더 파일이 포함 된 소스 파일은 헤더 파일이 변경 될 때마다 다시 컴파일해야합니다. 첫 번째 버전에서는 인터페이스를 변경해야하는 경우에만 헤더 파일을 변경합니다. 두 번째 버전에서는 인터페이스 또는 구현을 변경해야하는 경우 헤더 파일을 변경합니다.

당신이해야 외에 구현 세부 사항을 노출하지 , 당신은 얻을 것이다 불필요한 재 컴파일 두 번째 버전입니다.


1
+1 내 프로파일 러는 헤더 파일에 배치 된 코드를 계측하지 않습니다. 이는 귀중한 이유이기도합니다.
Eugene

이 질문에 대한 나의 대답을 보시면 programmers.stackexchange.com/questions/4573/… 당신은 그것이 클래스의 의미론에 어떻게 의존하는지, 즉 그것을 사용할 것인지 (특히 그것이 노출 된 부분 인 경우)를 볼 것입니다 사용자 인터페이스 및 시스템의 다른 클래스에서 직접 사용하는 클래스 수)
CashCow

3

나는 93-95 년에 두 번째로 그것을했습니다. 5-10 개의 함수 / 파일로 작은 앱을 재 컴파일하는 데 몇 분이 걸렸습니다 (동일한 486 PC에서 .. 아니, 수업에 대해 몰랐습니다. 14-15 세 였고 인터넷은 없었습니다 ) .

따라서 초보자에게 가르치는 것과 직업적으로 사용하는 것은 특히 C ++에서 매우 다른 기술입니다.

C ++과 F1 자동차의 비교는 적절하다고 생각합니다. 초보자는 F1 차량에 넣지 마십시오 (엔진을 80-95도까지 예열하지 않으면 시작되지 않습니다).

C ++을 모국어로 가르치지 마십시오. 옵션 2가 일반적으로 옵션 1보다 왜 나쁜지, 정적 컴파일 / 링크가 의미하는 바를 알고 C ++이 첫 번째 방법을 선호하는 이유를 충분히 이해해야합니다.


정적 컴파일 / 링크에 대해 조금 더 자세히 설명하면이 답변이 더 나을 것입니다 (당시에는 몰랐습니다!)
Felix Dombek

2

두 번째 방법은 완전히 인라인 된 클래스라고하는 것입니다. 클래스 정의를 작성하고 있지만이를 사용하는 모든 코드는 코드를 인라인합니다.

그렇습니다. 컴파일러는 인라인시기와하지 말아야 할시기를 결정합니다 ...이 경우 컴파일러가 결정을 내리는 데 도움이되고 실제로 코드를 적게 생성하고 더 빠르게 생성 할 수 있습니다.

이 장점은 함수의 구현을 수정하면 해당 함수를 사용하는 모든 소스를 다시 빌드해야한다는 사실보다 중요합니다. 클래스의 가벼운 특성상 구현을 수정하지 않을 것입니다. 새 메소드를 추가하면 어쨌든 헤더를 수정해야합니다.

그러나 수업이 더 복잡해지면서 루프를 추가 하더라도이 방법을 사용하면 이점이 줄어 듭니다.

여전히 다음과 같은 장점이 있습니다.

  • 이것이 "공통 기능"코드 인 경우 소스를 포함하는 라이브러리에 링크하지 않고도 헤더를 포함시켜 여러 프로젝트에서 사용할 수 있습니다.

인라인의 단점은 구현 세부 사항을 헤더로 가져와야한다는 것을 의미 할 때 문제가됩니다. 즉 추가 헤더를 포함해야합니다.

구현 세부 사항을 거의 포함해야하므로 템플릿은 특별한 경우입니다. 다른 파일에서는 모호 할 수 있지만 파일이 있어야합니다. (인스턴스를 사용하는 규칙에는 예외가 있지만 일반적으로 템플릿을 인라인합니다).


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.