본문 바로가기

C, C++/C++ 여행

C++ 여행 조언 새기기 3

A Tour of C++ 3장

 

모듈성에 관한 

 

1. 인터페이스로 쓰이는 선언과 구현으로 쓰이는 정의를 구분한다.

// add.h
int add(int a, int b);  // 선언만 포함
#include "add.h"

int add(int a, int b) {
    return a + b;  // 구현은 .cpp에 위치
}

헤더 파일과 소스 파일을 분리시켜 빌드 속도를 개선하고 재사용성을 높이자

 

 

2. module이 지원되는 헤더보다는 module이 낫다.

export module add;

export int add(int a, int b) {
    return a + b;
}

모듈 사용을 통해 불필요한 매크로, include 중복을 제거해 빌드 성능을 높인다

 

 

3. 헤더 파일로 인터페이스를 표현해 논리적 구조를 강조한다.

// logger.h (인터페이스)
#ifndef LOGGER_H
#define LOGGER_H

class Logger {
public:
    static void log(const std::string& message);
};

#endif
// logger.cpp (구현)
#include "logger.h"
#include <iostream>

void Logger::log(const std::string& message) {
    std::cout << message << std::endl;
}

 

 

4. 함수를 구현한 소스 파일에 헤더를 #include 한다.

: 1과 비슷

 

5. 인라인이 아닌 함수 정의는 헤더에 쓰지 않는다.

#ifndef MYFUNCTIONS_H
#define MYFUNCTIONS_H

// 함수 선언: 인터페이스만 제공
void foo();

// 인라인 함수는 헤더에 정의해도 됨
inline void bar() {
    // 인라인 함수 구현
}

#endif // MYFUNCTIONS_H

 

 

6. 네임 스페이스로 논리적 구조를 표현한다.

 

#ifndef MYLIBRARY_H
#define MYLIBRARY_H

namespace MyLibrary {
    // 함수 선언
    void foo();

    // 클래스 선언
    class Bar {
    public:
        void doSomething();
    };
}

#endif // MYLIBRARY_H
#include <iostream>
#include "MyLibrary.h"

namespace MyLibrary {
    // 함수 정의
    void foo() {
        std::cout << "MyLibrary::foo() 호출" << std::endl;
    }

    // 클래스의 멤버 함수 정의
    void Bar::doSomething() {
        std::cout << "MyLibrary::Bar::doSomething() 호출" << std::endl;
    }
}
#include "MyLibrary.h"

int main() {
    // 네임스페이스를 이용한 함수와 클래스 사용
    MyLibrary::foo();

    MyLibrary::Bar bar;
    bar.doSomething();

    return 0;
}

 

 

7. using 디렉티브는 전이나 기초 라이브러리에 사용하거나 지역 범위 안에 사용한다.

#include <iostream>

namespace A {
    void foo() {
        std::cout << "A::foo() 호출" << std::endl;
    }
}

namespace B {
    void foo() {
        std::cout << "B::foo() 호출" << std::endl;
    }
}

// 전역 범위에서 두 네임스페이스 모두의 이름을 가져옴
using namespace A;
using namespace B;

int main() {
    foo();  // 이름 충돌로 인한 모호성(ambiguous call)
    return 0;
}

 

8. using 디렉티브를 헤더 파일에 넣지 않는다.

-> 해당 헤더파일을 사용하면 using도 같이 사용되므로 혼란이 유발됨

 

9. 작은 값은 값으로, 큰 값은 참조로 전달한다.

-> 기본 자료형의 경우 크기가 작고 복사 비용이 낮지만, 크기가 큰 객체는 값으로 전달 시 오버헤드가 발생한다. 

따라서 참조 등으로 복사하는 것이 효율적이다.

 

10. 그냥 참조로 전달하기보다는 const 참조로 전달하는 편이 낫다.

-> const 사용 시 readonly라는 것을 명확히 전달할 수 있고, 실수를 막을 수 있다.

 

11. 값을 인수로 내보내지 말고 함수 반환값으로 반환한다.

#include <iostream>

// 결과를 출력 인수로 전달 (비권장)
void calculateSum(int a, int b, int& result) {
    result = a + b;
}

int main() {
    int sum = 0;
    calculateSum(3, 4, sum);
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}
#include <iostream>

// 결과를 함수의 반환값으로 전달 (권장)
int calculateSum(int a, int b) {
    return a + b;
}

int main() {
    int sum = calculateSum(3, 4);
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

 

12. 반환 타입 추론을 남용하지 말자.

13. 구조적 바인딩을 남용하지 말자. 반환 타입을 명명한 코드가 대개 더 읽기 쉽다.

'C, C++ > C++ 여행' 카테고리의 다른 글

[A Tour of C++] 7장 - 템플릿  (1) 2025.06.10
[A Tour of C++] 6장 - 필수 연산  (1) 2025.05.17
[A Tour of C++] 5장 - 클래스  (0) 2025.05.14
C++ 여행 조언 새기기 4  (0) 2025.02.22
C++ 여행 조언 새기기 2장  (0) 2025.02.16