C++ 클래스와 함수 선언부의 스타일은 코드 가독성과 유지보수성에 큰 영향을 줍니다. 클래스 내 멤버 변수를 어떤 순서로 배치할지, 접근제어 지정자(public, protected, private)를 어디에 놓을지, 함수 정의를 헤더 안에 둘 것인지 cpp 파일로 분리할 것인지, 그리고 함수 본문에서 중괄호 배치나 파라미터 정렬 방식을 어떻게 할지 등 다양한 결정 사항이 있습니다.
이번 글에서는 구글 C++ 스타일 가이드, LLVM 스타일 가이드, 모질라 스타일 가이드 등 다양한 스타일 가이드가 클래스 및 함수 인터페이스 디자인과 관련해서 어떤 규칙을 제안하는지 살펴봅니다. 또한 각 접근법의 장단점을 논하고, 상황에 따른 최선의 선택을 고민해봅니다.
다양한 스타일 가이드의 예
- 구글 C++ 스타일 가이드:
- 클래스에서는 public, protected, private 순으로 정렬하는 것을 자주 볼 수 있음
- 함수 정의는 가급적 cpp 파일로 분리하여 헤더는 인터페이스만 제공
- 짧고 단순한 inline 함수는 헤더에 둘 수 있으나, 헤더 부피 증가에 유의
- 중괄호 스타일은 K&R 스타일 권장 (함수 정의 시 반환 타입 아래 행에 본문 시작)
- LLVM 스타일 가이드:
- 클래스 멤버 순서에 대한 엄격한 규칙은 없으나, 관련 멤버끼리 묶고, 접근제어는 명확히 구분
- 함수 정의를 짧은 경우 헤더에 두기도 하지만 대체로 cpp 분리를 선호
- 중괄호 스타일은 LLVM 특유의 LLVM style (K&R 비슷하지만 세세한 부분 다를 수 있음)
- 모질라 스타일 가이드:
- 접근제어 지정자를 명확히 구분하고, 클래스 내에서 관련 멤버를 논리적으로 묶어 정렬
- 함수 본문은 가능한 한 분리, 헤더는 최소화 원칙 강조
- 중괄호 배치 역시 K&R에 가까운 형태 권장
이외에도 팀별로 public:를 맨 위에 두어 외부 인터페이스를 먼저 보여주거나, private:를 맨 위에 둬서 내부 구현 세부사항을 먼저 정의하는 식으로 하고 public:를 마지막에 두는 경우도 있습니다. 중요한 것은 일관성과 문서화입니다.
장점 및 단점 분석
클래스 멤버 순서
public -> protected -> private 순서
- 장점: 클래스 사용자가 가장 중요하게 볼 public 인터페이스를 맨 위에 배치해 가독성 향상
- 단점: 내부 구현 세부사항을 파악하려면 아래로 스크롤해야 함
private -> protected -> public 순서
- 장점: 클래스 구현 디테일을 먼저 정의하고, 나중에 공개 인터페이스를 확정하는 흐름으로 읽을 수 있음
- 단점: 사용자가 원하는 public API를 찾기 위해 스크롤 필요
멤버 변수, 멤버 함수 분리
- 멤버 함수를 먼저, 멤버 변수를 나중에 배치하는 경우
- 장점: 인터페이스(함수)와 구현의 주체(변수)를 분리해 논리적 구조 강화
- 단점: 변수 정의 위치가 함수와 멀어지면 가독성 저하 가능
함수 정의 위치(헤더 vs. cpp)
헤더에 함수 정의(inline 함수)
- 장점: 템플릿이나 짧은 유틸 함수의 경우 헤더에 정의하면 코드 이해가 편리하고 인라이닝에 유리
- 단점: 헤더 부피 증가, 빌드 시간 증가 가능, 구현 세부사항 노출
cpp 파일로 함수 정의 분리
- 장점: 인터페이스/구현 분리 명확, 빌드 시간 단축 가능(변경 시 재빌드 범위 축소), 캡슐화 강화
- 단점: 짧은 함수나 템플릿 함수 등은 분리 시 오히려 불편
중괄호 및 함수 본문 스타일
K&R 스타일(여는 중괄호는 같은 줄, 닫는 중괄호는 새 줄)은 많은 스타일 가이드에서 권장합니다.
- 장점: 널리 알려져 있고, C/C++ 커뮤니티에서 익숙
- 단점: 취향 문제, 일부 팀은 Allman 스타일(여는 중괄호를 다음 줄에) 선호
어떤 경우 어떤 선택을 할까?
- 대규모 프레임워크, 라이브러리: public 인터페이스를 맨 위에 두고, 그 아래에 내부 구현(private) 배치. 함수는 cpp 분리로 빌드 시간 및 모듈성 확보.
- 템플릿 기반 라이브러리: 구현을 헤더에 두어야 할 경우가 많으므로, inline 함수나 템플릿 메타프로그래밍 코드는 헤더 안에 유지. 클래스 멤버 순서와 주석으로 가독성 확보.
- 작은 유틸리티 클래스: 모든 것이 간결하다면 클래스 선언부에 바로 함수 정의(=inline)하는 것도 가능하지만, 대규모 확장에는 비권장.
어떤 스타일을 택하든지, 팀 합의와 자동화된 코드 포매터(tool: clang-format 등) 사용을 통해 일관성을 유지하는 것이 중요합니다.
실제 예제 코드 비교
// 예: public -> protected -> private 순서, 함수 본문은 cpp로 분리
class MyClass {
public:
MyClass();
void DoSomething();
protected:
void HelperFunction();
private:
int data_;
};
// 예: 템플릿 클래스, 헤더에 함수 정의(인라인)
template<typename T>
class MyContainer {
public:
void Add(const T& item) {
items_.push_back(item); // 짧고 단순한 함수는 헤더에 둠
}
private:
std::vector<T> items_;
};
마무리
클래스와 함수 인터페이스 스타일은 코드를 어떻게 구조화하고, 사용하는 이에게 어떤 정보를 먼저 제공할지 결정하는 중요한 요소입니다. 접근제어 지정자 순서, 함수 정의 위치, 중괄호 스타일 등은 정답이 없지만, 팀 문화, 프로젝트 규모, 빌드 환경을 고려해 합리적인 결정을 내리고, 일관성 있게 유지하는 것이 핵심입니다.
다음 편에서는 주석 스타일, 문서화 규칙, 도큐멘테이션 도구(Doxygen, Javadoc 스타일 주석) 등에 대해 살펴보며, 주석 관련 코드 스타일 이슈를 다루어보겠습니다.
'개발 이야기 > C++' 카테고리의 다른 글
[C++ 스타일 6편] 템플릿, Concepts, 그리고 메타프로그래밍 코드의 스타일 (0) | 2024.12.15 |
---|---|
[C++ 스타일 5편] 주석과 문서화: Doxygen, Javadoc, 단문 주석 스타일 (0) | 2024.12.15 |
[C++ 스타일 3편] 헤더 파일 구조: #include 순서, 전방 선언, 헤더 가드 vs. #pragma once (0) | 2024.12.15 |
[C++ 스타일 2편] 네이밍 컨벤션: 변수명, 함수명, 클래스명, 그리고 언더스코어 vs. 카멜케이스 (1) | 2024.12.15 |
[C++ 스타일 1편] 들여쓰기와 공백 규칙: 스페이스 vs. 탭, 그리고 라인 길이 (0) | 2024.12.15 |