C++ 에서 헤더 내에 클래스의 선언과 정의가 모두 있는 경우는 무엇인가요?

awidesky의 이미지

C/C++에서는 함수의 선언과 정의를 .cpp, .h에 구분해 놓는다고 배웠습니다.
막상 찾아보면 그렇지 않은 경우가 많은것 같아 햇갈립니다;;
https://github.com/awidesky/cyclone-physics/blob/master/include/cyclone/core.h
여기에서도 Vecter3 클래스의 함수가 다 선언되어 있네요;;
그냥 다 헤더에 때려넣고 파일 개수를 줄이려 한 줄 알았는데... core.cpp도 따로 있더군요(?!??)
https://github.com/awidesky/cyclone-physics/blob/master/src/core.cpp
헤더에 선언부만 넣는 경우와 정의도 다 때려넣는 겅우의 기준(?)이 궁금합니다.

Stephen Kyoungwon Kim@Google의 이미지

정의를 다 넣게 되면 문제가 생길 수 있습니다. core.h를 foo.cpp와 bar.cpp에 각각 include하는 경우를 생각해 보죠. 정의가 foo.cpp에도 bar.cpp에도 각각 들어가게 됩니다. 따라서 나중에 foo.o와 bar.o를 링크하게 되면 multiple definitions로 링킹 타임 에러가 나게 됩니다.

일반적으로는 선언은 .h 파일에, 정의는 .cpp 파일에 넣는 게 좋습니다.

이 코드는 cyclone.h를 여러 개의 cpp 파일에서 인클루드 하게 되면 문제가 생길 것처럼 보이네요.

정의가 .h 파일에 들어가 있어도 안전하거나 그렇게 해야 하는 경우도 몇 가지 있습니다. 주로 컴파일러가 예컨대 bar.cpp를 컴파일하는 동안 선언 이상의 것을 알아야 하는 경우가 거기에 해당됩니다.

대표적인 경우는 템플릿과 inline 함수입니다.

extern int core(int x);
 
int foo() {
  auto i = core(210);
  return i + 3;
}

위의 코드에서 컴파일러는 core가 int를 리턴하고 int를 받는 함수라는 것만 알아도 foo를 컴파일하는 데는 문제가 없습니다. 하지만 아래는 얘기가 다릅니다.

template<typename T>
int core(T x);
 
int foo() {
  auto i = core<int>(210);
  return i + 3;
}

템플릿의 경우 사용자가 그 함수, core를 완전히 만드는 게 아니라 컴파일러에게 컴파일 직전 그 함수를 어떻게 만들지 알려줄 뿐입니다. 컴파일러는 core(210)를 보는 순간, 템플릿 정의를 보고 core라는 이름의, int를 받아 int를 리턴하는 함수를 그때 생성하게 됩니다. 그래서 이 템플릿 정의는 foo를 컴파일할 때 반드시 보여야 합니다.

인라인도 마찬가집니다. 인라인은 컴파일러가 함수 호출 자리에 호출되는 함수의 내용을 갈아 끼워넣는 것인데 함수의 내용을 모른다면 할 수가 없죠.

정의를 헤더에 다 집어넣는 건 일반적으로는 좋은 습관 같진 않습니다. inline이나 template이 아니라면요.

익명 사용자의 이미지

Quote:
C/C++에서는 함수의 선언과 정의를 .cpp, .h에 구분해 놓는다고 배웠습니다.

C++언어에서 위 가이드라인은 매우 많이 간략화된 것입니다.
정확한 규칙을 확인하기 위해서는 One-Definition Rule (ODR)을 확인해야 합니다.

https://en.cppreference.com/w/cpp/language/definition

일반적으로 class definition은, 그 클래스를 "사용"하는 거의 모든 코드에서 필요한 경우가 많습니다. 이는 현실적인 이유 때문인데, definition이 없으면 해당 class instance의 크기조차 알 수 없기 때문이지요. C++ 문법에서 이는 "incompletely-defined object type"으로 나타나며, 그 사용처가 상당히 제한됩니다.

이러한 이유로 C++에서는 클래스의 정의가 여러 해석 단위에 나타나는 것을 허용합니다. 다만, 동일한 클래스의 정의는 "동일"해야 합니다. (디테일은 생략합니다.) 현실적으로 이는 클래스 정의를 헤더 파일에 두어 여러 소스 파일에서 include하는 형태로 구현됩니다.

경우에 따라서, private field 및 method까지 고스란히 헤더 파일에 올라가 모든 소스 파일들이 의존하게 된다는 점이 별로 달갑지 않은 경우가 있는데, 그런 경우 PImpl 같은 패턴을 쓰시면 됩니다.

https://en.cppreference.com/w/cpp/language/pimpl

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.