Functions

Inputs and Outputs

함수의 출력은 자연스럽게 반환 값을 통하며, 때로는 매개 변수를 통해 제공한다.

매개변수 보다 반환 값을 사용하는 것을 선호한다.

  • 가독성을 향상시키고 종종 동일하거나 더 나은 성능을 제공
  • Null 이 될 수 없는 한 원시 포인터를 반환하지 않음

std::optional을 사용하여 값에 의한 선택적 입력을 나타내고, 비 선택적일 때 const 포인터를 사용한다.

Write Short Functions

가능한 짧고 단순하게 작성하여 작고 집중된 기능으로 구현한다.

  • 단, 함수를 구성하는 코드 길이에 대한 제한은 없다.
  • 40 줄을 초과하는 경우에는 프로그램의 구조를 해치지 않고 분해할 수 있는지 고민해보길 권유
  • 함수를 짧고 단순하게 유지하면 다른 사람들이 코드를 더 쉽게 읽고 수정할 수 있음
  • 기능 별로 나눠두면 테스트 하기에 용이함

Function Overloading

함수 오버로딩을 사용할 때는 호출하는 코드만 보고도 어떤 함수가 실행 될지 쉽게 알 수 있어야 한다.

  • 예시 1. 함수의 의미가 다른데 적절하지 않게 오버로딩을 사용한 경우
void Process(int value);
void Process(double value);
void Process(bool flag);
void Process(const std::string& str);
void Process(const std::vector<int>& data);

 

const 또는 & (래퍼런스)로 인한 오버로딩은 유용하게 활용이 가능하다.

 

class Widget {
 public:
  void PrintInfo() &;   // 인스턴스에서 호출 가능
  void PrintInfo() &&;  // 임시 객체에서만 호출 가능
};

Widget w;
w.PrintInfo();  // ✅ PrintInfo() & 호출됨
Widget().PrintInfo();  // ✅ PrintInfo() && 호출됨

Default Arguments

가독성을 높이는 데 유용하지만, 오버로딩과 비교하여 신중하게 선택해야한다.

가상(virtual) 함수에서는 사용하지 않는다.

class Base {
public:
    virtual void Speak(std::string msg = "Hello from Base!") {
        std::cout << msg << std::endl;
    }
};

class Derived : public Base {
public:
    void Speak(std::string msg = "Hello from Derived!") override {
        std::cout << msg << std::endl;
    }
};

int main() {
    Derived d;
    Base* b = &d;
    
    b->Speak();  // "Hello from Base!" 출력 (❌ 예상과 다름)
}

Trailing Return Type Syntax

람다(lambda) 함수와 같이 특정 상황에서만 필요한 선언 스타일로, 일반적으로는 선행 반환 타입(Leading Return Type)을 사용한다.

  • 선행 반환 타입과 후행 반환 타입(Trailing Return Type)
int foo(int x); // 선행 반환 타입
auto foo(int x) -> int; // 후행 반환 타입, C++ 11 이상
  • 람다에서 반환 타입을 명시할 때는 반드시 후행 타입을 사용
  • 생략하면 컴파일러가 자동으로 반환 타입을 추론
auto lambda = [](int x, int y) -> int {
    return x + y;
};
  • 템플릿에서 반환 타입이 매개변수에 따라 달라질 때 사용
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u);

+ Recent posts