Company
교육 철학

LV11 템플릿(template), 연산자 오버로딩

템플릿(Template)과 연산자 오버로딩

일반화 프로그래밍(Generic Programming)

핵심 개념: 다양한 타입에서 동작하는 하나의 코드를 작성하는 것
객체 지향: 데이터 중심
일반화 프로그래밍: 알고리즘 중심
목표: 타입마다 별도 함수/클래스를 만들지 않고 범용적으로 사용

템플릿(Template)이란?

매개변수의 타입에 따라 함수나 클래스를 자동 생성하는 메커니즘
*매개변수화 타입(parameterized type)**이라고도 불림
컴파일 시점에 실제 타입으로 대체됨

변수 템플릿

타입에 따라 다른 값을 가지는 변수
// variable template template <typename T> constexpr T pi = T(3.1415926535897932385L); int main() { float f = pi<float>; // float 버전의 pi double d = pi<double>; // double 버전의 pi int i = pi<int>; // int 버전의 pi (3) return 0; }
C++
복사

함수 템플릿

같은 알고리즘, 다른 타입에서 동작하는 함수

기본 문법

template <typename T> 반환타입 함수이름(T 매개변수) { // 함수 본체 }
C++
복사

실제 사용 예시

// ❌ 기존 방식: 타입마다 별도 함수 필요 //int Add(int a, int b) { return a + b; } //float Add(float a, float b) { return a + b; } // ✅ 템플릿 방식: 하나의 함수로 모든 타입 처리 template <typename T> T Add(T a, T b) { return a + b; } int main() { int a = Add<int>(1, 2); // int 버전 호출 float b = Add<float>(1.0f, 2.0f); // float 버전 호출 return 0; }
C++
복사
컴파일러 동작:
Add<int>(1, 2) 호출 시: ├─ 컴파일러가 int 버전의 Add 함수 자동 생성 └─ int Add(int a, int b) { return a + b; }
Plain Text
복사

명시적 특수화(Explicit Specialization)

특정 타입에 대해서만 다른 동작 정의
template <typename T> void Swap(T& a, T& b) { T temp = a; a = b; b = temp; } // double 타입에 대한 특별한 처리 template <> void Swap<double>(double& a, double& b) { // double형은 값을 서로 바꾸지 않음 std::cout << "double은 교환하지 않습니다!" << std::endl; }
C++
복사

클래스 템플릿

다양한 타입의 데이터를 저장할 수 있는 클래스
template <typename T> class Data { public: T GetData() { return mData; } void SetData(T data) { mData = data; } private: T mData; // T 타입의 데이터 저장 }; int main() { Data<int> intData; // int용 Data 클래스 Data<float> floatData; // float용 Data 클래스 intData.SetData(100); floatData.SetData(3.14f); return 0; }
C++
복사

가변인자 템플릿 (C++11)

임의의 개수와 타입의 매개변수를 받는 템플릿

기본 문법

template <typename... Args> // Args: 타입들의 집합 void function_name(Args... args) // args: 실제 값들의 집합 { // 함수 본체 }
C++
복사

재귀적 처리 방식

#include <iostream> #include <print> #include <vector> // 재귀 종료 조건 void print() { std::cout << std::endl; } // 가변인자 템플릿 함수 template <typename T, typename... Args> void print(T first, Args... args) { std::cout << first << " "; print(args...); // 나머지 인자로 재귀 호출 } int main() { print(1, "Hello", 3.14, 'A'); // "1 Hello 3.14 A" 출력 return 0; }
C++
복사

C++17 Fold Expressions

#include <iostream> #include <print> #include <vector> template <typename... Args> auto sum(Args... args) { // print args... return (... + args); // 모든 인자를 더함 } template <typename... Args> void printAll(Args... args) { (std::print("{} ", args), ...); // 모든 인자를 출력 std::print("\n"); } int main() { int result = sum(1, 2, 3, 4, 5); // 15 반환 printAll(1, 2, 3, 4, 5); // "1 2 3 4 5" 출력 return 0; }
C++
복사

템플릿으로 연결리스트 만들기

제네릭 연결리스트 구현
#include <iostream> #include <print> #include <vector> #include <list> namespace ya { template <typename T> class list { public: struct Node { T data; // 제네릭 데이터 Node* back; // 다음 노드 포인터 }; list() // 생성자 { mHead = nullptr; mTail = nullptr; } ~list() // 소멸자 { // 메모리 해제 코드 필요 } void push_back(T data) { if (mHead == nullptr) // 첫 번째 노드 { mHead = new Node(); mHead->data = data; mHead->back = nullptr; mTail = mHead; } else // 기존 노드가 있는 경우 { mTail->back = new Node(); mTail->back->data = data; mTail->back->back = nullptr; mTail = mTail->back; } } private: Node* mHead; // 첫 번째 노드 Node* mTail; // 마지막 노드 }; } int main() { ya::list<int> intList; // int용 리스트 intList.push_back(1); intList.push_back(2); std::list<int> stdList; // std::list 사용 예시 stdList.push_back(1); stdList.push_back(2); return 0; }
C++
복사

연산자 오버로딩(Operator Overloading)

기존 연산자에 새로운 의미를 부여하는 기법

기본 문법

타입 operator연산자기호(매개변수) { // 연산자 동작 정의 }
C++
복사

오버로딩 가능한 연산자들

카테고리
연산자들
산술
+, -, *, /, %
대입
=, +=, -=, *=, /=
비교
==, !=, <, >, <=, >=
논리
&&, `
기타
[], (), ->, ++, --

오버로딩 불가능한 연산자들

. (멤버 선택)
:: (범위 지정)
?: (삼항 연산자)
sizeof

실제 구현 예시

Point 구조체 연산자 오버로딩

struct Point { int x, y; // ➕ 덧셈 연산자 Point operator+(Point other) { Point result; result.x = x + other.x; result.y = y + other.y; return result; } // ➖ 뺄셈 연산자 (Point - Point) Point operator-(Point other) { Point result; result.x = x - other.x; result.y = y - other.y; return result; } // ➖ 뺄셈 연산자 (Point - int) Point operator-(int value) { Point result; result.x = x - value; result.y = y - value; return result; } // 🔍 비교 연산자 bool operator<(Point other) { return (x < other.x && y < other.y); } }; int main() { Point p1 = {1, 1}; Point p2 = {3, 2}; Point p3 = p1 + p2; // p1.operator+(p2) 호출 Point p4 = p1 - p2; // p1.operator-(p2) 호출 Point p5 = p1 - 5; // p1.operator-(5) 호출 if (p1 < p2) { // p1.operator<(p2) 호출 std::cout << "p1이 p2보다 작습니다" << std::endl; } return 0; }
C++
복사

Complex 수 연산자 오버로딩

struct Complex { double re, im; // 실수부, 허수부 Complex(double r, double i) : re(r), im(i) {} void Display() { std::cout << re << " + " << im << "i" << std::endl; } // 복소수 덧셈 Complex operator+(Complex& other) { return Complex(re + other.re, im + other.im); } }; int main() { Complex a(1.2, 3.4); // 1.2 + 3.4i Complex b(5.6, 7.8); // 5.6 + 7.8i Complex c = a + b; // (6.8, 11.2) c.Display(); // "6.8 + 11.2i" 출력 return 0; }
C++
복사

숙제 안내

ya::list 구조 분석

ya::list를 3번 따라 치며 디버깅
메모리 구조 그림 그리기

ya::list 기능 확장

yaList.push_front(10); // 앞쪽에 추가하는 함수 int len = yaList.size(); // 크기 반환하는 함수
C++
복사

Iterator 구현 (고급)

for (ya::list<int>::iterator iter = yaList.begin(); iter != yaList.end(); ++iter) { std::cout << *iter << std::endl; }
C++
복사

Vector2 연산자 오버로딩

struct Vector2 { double x, y; explicit Vector2(double x_, double y_) : x(x_), y(y_) {} // 10가지 이상의 연산자 구현하기 // ==, !=, +, -, *, /, +=, -=, *=, /=, <, >, <= 등 };
C++
복사
핵심 포인트:
템플릿: 하나의 코드로 여러 타입 지원
연산자 오버로딩: 사용자 정의 타입에 직관적인 연산 제공
제네릭 프로그래밍: 재사용성과 타입 안전성 확보