[Day13] From Function Overloading to C++ Templates

베리투스·2025년 8월 21일

TIL: Today I Learned

목록 보기
21/93

C++의 강력한 코드 재사용 도구인 템플릿(Template)에 대해 학습했다. 템플릿을 사용하면 int, double, string다양한 자료형에 대해 동작하는 일반화된 함수나 클래스를 한 번만 정의하여 사용할 수 있다는 것을 배웠다. 🔥 이를 통해 타입별로 여러 개의 함수를 만들어야 했던 함수 오버로딩의 번거로움을 해결하고, 코드의 중복을 줄여 생산성과 유지보수성을 크게 향상시키는 방법을 익혔다. 💻


📌 목표

  • 함수 오버로딩의 개념과 규칙 이해
  • 템플릿을 사용하여 타입에 독립적인 함수(함수 템플릿) 작성
  • 템플릿을 사용하여 타입에 독립적인 클래스(클래스 템플릿) 작성
  • 코드의 재사용성을 높이는 프로그래밍 방식 학습

📖 이론

1. 함수 오버로딩 (Function Overloading)

  • 정의: 동일한 스코프 내에서 같은 이름을 가진 함수를 여러 개 정의하는 것.
  • 조건: 함수의 이름은 같지만, 매개변수의 개수나 타입이 달라야 한다. 컴파일러는 함수 호출 시 전달된 인자의 타입과 개수를 보고 어떤 함수를 호출할지 결정한다.
  • 주의: 반환 타입만 다른 경우는 오버로딩이 성립하지 않는다.
  • 한계: 기능은 동일한데 단지 처리할 데이터 타입만 다른 경우, 타입별로 함수를 일일이 만들어야 해서 코드 중복이 발생한다. 예를 들어, int를 더하는 add, double을 더하는 add 함수를 각각 만들어야 한다.

2. 함수 오버로딩 호출 규칙

  • 컴파일러는 오버로딩된 함수 중 어떤 것을 호출할지 결정할 때 다음과 같은 우선순위를 따른다.
    1. 정확한 타입 일치: 인자의 타입과 정확히 일치하는 매개변수를 가진 함수를 최우선으로 찾는다.
    2. 타입 승격: 정확한 타입이 없으면, 데이터 손실이 없는 방향으로의 자동 형 변환(e.g., char -> int, float -> double)이 가능한 함수를 찾는다.
    3. 표준 타입 변환: 데이터 손실이 발생할 수 있는 형 변환(e.g., double -> int)이 가능한 함수를 찾는다.
    4. 사용자 정의 변환: 클래스에 정의된 변환 연산자를 통한 변환이 가능한 함수를 찾는다.
  • 만약 호출이 애매모호(ambiguous)한 경우(e.g., 두 개 이상의 함수가 동일한 우선순위로 후보가 될 때) 컴파일 오류가 발생한다.

3. 템플릿 (Template)

  • 정의: 타입에 의존하지 않는 일반적인(generic) 코드 작성을 가능하게 하는 C++의 기능이다. 함수나 클래스를 "틀(template)"처럼 만들어두고, 실제 사용 시점에서 타입을 지정하여 코드를 생성한다.
  • 목표: 코드 중복을 줄이고 재사용성을 극대화한다.

4. 함수 템플릿 (Function Template)

  • 특정 타입에 국한되지 않고, 다양한 타입의 인자를 처리할 수 있는 일반화된 함수를 정의하는 방법이다.
  • template <typename T> 또는 template <class T> 키워드를 함수 정의 앞에 붙여 사용한다. 여기서 T는 "타입 매개변수"로, 실제 함수 호출 시 컴파일러가 인자의 타입을 보고 T를 구체적인 타입(int, double 등)으로 대체하여 코드를 생성한다.

5. 클래스 템플릿 (Class Template)

  • 다양한 타입을 처리할 수 있는 일반화된 클래스를 정의하는 방법이다.
  • 클래스 정의 앞에 template <typename T>를 붙여 선언한다.
  • 클래스 템플릿을 사용하여 객체를 생성할 때는 Array<int> arr; 와 같이 <> 안에 사용할 타입을 명시적으로 지정해주어야 한다.

💻 코드

1. 함수 오버로딩 vs 함수 템플릿

함수 오버로딩으로 구현한 add 함수

#include <iostream>
#include <string>

// 각 타입에 맞춰 개별적으로 함수를 정의해야 함
int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

std::string add(const std::string& a, const std::string& b) {
    return a + b;
}

함수 템플릿으로 구현한 add 함수

#include <iostream>
#include <string>

// template 키워드를 사용하여 하나의 일반화된 함수를 정의
template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    // 컴파일러가 인자를 보고 T를 각 타입(int, double, string)으로 추론하여 코드를 생성
    std::cout << "3 + 5 = " << add(3, 5) << std::endl;
    std::cout << "2.5 + 4.3 = " << add(2.5, 4.3) << std::endl;
    std::cout << "Hello + World = " << add(std::string("Hello"), std::string("World")) << std::endl;
    return 0;
}

2. 클래스 템플릿 예제

#include <iostream>

// 어떤 타입(T)의 데이터든 저장할 수 있는 일반화된 Array 클래스
template <typename T>
class Array {
private:
    T data[100]; // T 타입의 데이터를 저장할 배열
    int size;

public:
    Array() : size(0) {}

    void add(const T& element) {
        if (size < 100) {
            data[size++] = element;
        }
    }

    void print() const {
        for (int i = 0; i < size; ++i) {
            std::cout << data[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    // int 타입을 저장하는 Array 객체 생성
    Array<int> intArray;
    intArray.add(10);
    intArray.add(20);
    std::cout << "Int Array: ";
    intArray.print();

    // double 타입을 저장하는 Array 객체 생성
    Array<double> doubleArray;
    doubleArray.add(3.14);
    doubleArray.add(2.71);
    std::cout << "Double Array: ";
    doubleArray.print();

    return 0;
}

⚠️ 실수

  • 함수 오버로딩 시, 반환 타입만 다르게 해서는 오버로딩이 되지 않는다는 점을 잊고 코드를 작성했다가 컴파일 에러를 만났다. 😅 컴파일러는 함수를 호출할 때 인자만 보기 때문에 반환값으로는 함수를 구분할 수 없다는 것을 명심해야겠다.
  • 템플릿 클래스로 객체를 만들 때, Array arr; 와 같이 타입을 명시하지 않고 사용하려다 오류를 겪었다. 클래스 템플릿은 함수 템플릿과 달리 컴파일러가 타입을 자동으로 추론해주지 않으므로, Array<int> arr; 처럼 사용할 타입을 <> 안에 명시적으로 지정해야 한다는 것을 배웠다.
  • template <typename T>를 선언하고 나서, 함수나 클래스 내부에서 T 대신 무심코 int 같은 구체적인 타입을 써서 템플릿의 의미를 무색하게 만드는 실수를 했다. 템플릿을 사용하기로 했으면, 일반화가 필요한 모든 곳에 타입 매개변수(T)를 일관되게 사용해야 한다.

✅ 핵심 요약

개념설명비고
함수 오버로딩이름은 같지만 매개변수의 타입이나 개수가 다른 함수를 여러 개 정의하는 것.반환 타입만 다른 것은 불가.
템플릿 (Template)타입에 독립적인 일반화된 코드를 작성하게 해주는 C++ 기능.코드 재사용성 극대화.
template <typename T>"어떤 타입이든 올 수 있으며, 그 타입을 지금부터 T라고 부르겠다"는 선언.typename 대신 class도 사용 가능.
함수 템플릿다양한 타입에 대해 동작하는 하나의 함수를 정의. 컴파일러가 호출 시 타입을 추론한다.add<int>(3, 5)처럼 명시적 호출도 가능.
클래스 템플릿다양한 타입을 멤버로 가질 수 있는 하나의 클래스를 정의. 객체 생성 시 타입을 명시해야 한다.MyClass<int> obj;
profile
Shin Ji Yong // Unreal Engine 5 공부중입니다~

0개의 댓글