[TIL] 2025-12-17 | C++ 예외 처리, 연산자 오버로드, 객체지향적 설계

2025. 12. 17. 17:13·내배캠Unreal_TIL/C++
게임 개발자를 위한 C++ 문법 2-4

도전 실습 어렵게 생각하니 갱장히 어렵네요,,

1. WHAT

- thorw: 예외 발생

throw out_of_range("Array index out of range");

out_of_range, overflow_error, length_error, runtime_error

-> throw한 위치에서 즉시 함수 종료, 예외 처리 부분으로 이동

 

- try - catch: 예외 처리

try {
	arr[0] = 10;
	arr[1] = 20;
	arr[2] = 30;
	arr[5] = 40; //예외 처리
	arr[3] = 50; //실행 X
} catch (const out_of_range& e){
	cout << "ERROR: " << e.what() << endl;
}

예외 발생 X ->  catch문 무시

예외 발생 O -> stack에 생성된 모든 객체의 소멸자 호출, 가까운 catch문으로 이동 -> 예외에 관한 내용 what()으로 확인

예외를 생성자에서 던질 때 주의해야 할 점
생성자에서 예외가 발생 시에 소멸자가 호출되지 않는다!
만일 예외를 던지기 이전에 획득한 자원이 있다면 catch에서 해제시켜야 한다.

 

- Range-based for loop: 처음부터 끝까지 순회

for ( 데이터 타입 elem: 데이터 리스트){
	elem을 이용한 순회
}

 

 

- 객체지향적 설계

  • 응집도: 클래스 또는 모듈 내부의 구성 요소들이 얼마나 밀접하게 관련되어 있는지
  • 결합도: 모듈 또는 클래스 간의 의존성
  • SOLID 원칙
    • SRP 단일 책임 원칙: 각 클래스는 하나의 책임만!
    • OCP 개방 폐쇄 원칙: 확장에는 열려있고 수정에는 닫혀있어야 함
    • LSP 리스 코프 치환 원칙: 자식 클래스는 부모 클래스에서 기대되는 행동 보장
    • ISP 인터페이스 분리 원칙: 클라이언트는 자신이 사용하지 않는 메서드에 의존X
    • DIP 의존 역전 원칙: 고수준 모듈은 저수준 모듈에 직접 의존X, 두 모듈 모두 추상화에 의존

 

⁉️ DB 정규화처럼.. 객체지향 설계도 많이 나누면 성능에 문제가 없을까에 대한 궁금증

더보기

✅ 클래스를 쪼개야 할 때

  • 변경 이유가 다를 때
  • 재사용 가능성이 명확할 때
  • 정책/규칙/행위가 포함될 때
  • 테스트 단위로 분리할 수 있을 때

❌ 쪼개지 말아야 할 때

  • 단순 데이터 묶음일 뿐일 때
  • 항상 함께 생성·삭제·변경될 때
  • 의미 없는 위임만 생길 때
  • 클래스 이름이 설명하기 어려울 때

DB 정규화는 데이터 무결성을 위해 구조를 쪼개고, 객체지향 설계는 변경 이유를 기준으로 책임을 쪼갠다.
둘 다 과하면 오히려 성능과 생산성을 해친다.

 

 

2. RESULT

  • 도전 실습 2-1
#include <iostream>
#include <memory>

using namespace std;

class Data
{
public:
    int value;

    Data(int v) : value(v)
    {
        cout << "[INFO] Data(" << value << ") 객체 생성됨.\n";
    }

    ~Data()
    {
        cout << "[INFO] Data(" << value << ") 객체 소멸됨.\n";
    }
};


void RepresentDanglingPointer()
{
    std::cout << "\n === 메모리 테스트 ===\n";

    // 1. 힙에 Data 객체를 할당하고, 두 개의 Raw Pointer에 주소를 저장하세요.
    Data* raw_ptr1 = new Data(43);
    Data * raw_ptr2 = raw_ptr1;

    cout << "Raw Ptrs 값: " << raw_ptr1->value << "\n";
    // 2. raw_ptr1을 사용하여 메모리를 해제합니다.
    delete raw_ptr1;
    cout << "raw_ptr1로 메모리 해제 완료.\n";

    // 3. raw_ptr2를 이용하여 메모리를 해제합니다.
    // 런타임 에러(Crash)를 유발할 수 있습니다.
    cout << "raw_ptr2로 해제 시도...\n";
    delete raw_ptr2;
}
void SharedPointer()
{
    std::cout << "\n === 메모리 테스트 ===\n";

    // 1. 힙에 Data 객체를 할당하고, 두 개의 Pointer에 주소를 저장하세요.
    shared_ptr<Data>ptr1 = make_shared<Data>(43);
    shared_ptr<Data>ptr2 = ptr1;

    cout << "Ptrs 값: " << ptr1->value << "\n";
    // 2. ptr1 소유권을 해제 (참조 카운트 감소)
    ptr1.reset();
    cout << "ptr1로 메모리 해제 완료.\n";

    // 3. ptr2 소유권을 해제 (참조 카운트 감소)
    cout << "ptr2로 해제 시도...\n";
    ptr2.reset();
}

int main() {
    SharedPointer();
    return 0;
}

 

  • 도전 실습 2-2
// 인덱스 연산자 []를 오버로딩하여 구현 - 읽기/쓰기
#include <iostream>
using namespace std;

template <typename T>
class Array {
    T data[100];
    int size;
public:
    Array() : size(0) {}

    T& operator[](int index) {
        if (index<0|| size < index) {
            throw out_of_range("Array index out of range");
        }
        if (index==size)
            size++;
        return data[index];
    }
    void add(const T& element) {
        if (size < 100)
            data[size++] = element;
    }

    void remove() {
        if (size > 0)
            size--;
    }

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

int main() {
    Array<int> arr; // 정수형 배열 생성
    try {
        arr[0] = 10;
        arr[1] = 20;
        arr[2] = 30;
        arr[5] = 40; //예외 처리
        arr[3] = 50; //실행 X
    }
    catch (const out_of_range& e){
        cout << "ERROR: " << e.what() << endl;
    }
    arr.print();
    cout << arr[0] << endl;
    return 0;
}

읽기와 쓰기에 대해서도 구분하고 싶었는데... 그럼 연산자 오버로딩을 더 깊에 들어가야해서 너무 어렵다..ㅠㅠㅠㅠㅠ

연산자 오버로딩 더 공부해야겠다...

 

  • 도전X도전 실습 2-2
// 제공되는 코드에 foreach를 동작시키기 위해 필요한 함수를 추가
#include <iostream>
#include <vector>
using namespace std;

template <typename T>
class Array {
    T data[100];
    int size;
public:
    Array() : size(0) {}

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

    void remove() {
        if (size > 0)
            size--;
    }

    void print() {
        vector <T> temp(data, data + size);
        for (T item : temp) { // Range-based for loop
            cout << item << " ";
        }
        cout << endl;
    }
};

int main() {
    Array<int> arr; // 정수형 배열 생성
    arr.add(10);
    arr.add(20);
    arr.add(30);
    arr.print();

    arr.remove();
    arr.print();
    return 0;
}

// 출력결과:
// 10 20 30
// 10 20

제대로 한게 맞나....? --> 튜터님 찾아감

  • 2주차 숙제

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

struct Movie {
    string title;
    double rating;
};

// TODO: MovieProcessor 추상 클래스 정의
// 순수 가상 함수 process를 선언해야 합니다.
// process는 vector<Movie>&를 인자로 받아야 합니다.
class MovieProcessor {
public:
    virtual void process(vector<Movie>& movies) = 0;
    virtual ~MovieProcessor() {} //소멸자 까먹음 !!!!
};

// 기본 영화 관리자
class MovieManager {
private:
    vector<Movie> movies;
    map<string, double> movieMap;

public:
    MovieManager() {
        // 초기 데이터 설정
        movies = {
            {"Inception", 9.0},
            {"Interstellar", 8.6},
            {"The Dark Knight", 9.1},
            {"Memento", 8.4}
        };

        for (const auto& movie : movies) {
            movieMap[movie.title] = movie.rating;
        }
    }

    void printMovies() {
        cout << "영화 목록:\n";
        for (const auto& movie : movies) {
            cout << "제목: " << movie.title << ", 평점: " << movie.rating << "\n";
        }
    }

    void findMovie(const string& title) {
        auto it = movieMap.find(title);
        if (it != movieMap.end()) {
            cout << "영화 제목: " << it->first << ", 평점: " << it->second << "\n";
        }
        else {
            cout << "해당 영화는 목록에 없습니다.\n";
        }
    }

    // MovieProcessor를 사용하여 기능 확장
    void processMovies(MovieProcessor& processor) {
        processor.process(movies);
    }
};


// TODO: compareMovies 함수 정의
// Movies 객체의 대소를 비교하는 함수 입니다.
// STL에서 제공하는 sort 함수를 활용해서 vector<Movie>를 멤버변수 rating 기준 내림차순으로 정렬 할 수 있도록 해야 합니다. 
bool compareMovies(const Movie& a, const Movie& b) {
    return a.rating > b.rating;
}

// TODO: RatingSorter 클래스 정의
// MovieProcessor를 상속받아 구현합니다.
// process 는 vector<Movie>&를 인자로 받으며 영화목록이 저장되어 있습니다.
// process는 인자로 받은 벡터는 내림차순으로 정렬하고, 정렬된 영화목록을 출력합니다.
class RatingSorter : public MovieProcessor {
public:
    void process(vector<Movie>& movies) {
        sort(movies.begin(), movies.end(), compareMovies);
        cout << "평점 기준 정렬된 영화 목록:" << endl;
        for (const auto& movie : movies) {
            cout << "제목: " << movie.title << ", 평점: " << movie.rating << endl;
        }
    }
};

// 구체 클래스: 특정 평점 이상의 영화 필터링
class RatingFilter : public MovieProcessor {
private:
    double minRating;

public:
    explicit RatingFilter(double minRating) : minRating(minRating) {}

    void process(vector<Movie>& movies) {
        cout << "평점 " << minRating << " 이상인 영화 목록:\n";
        for (const auto& movie : movies) {
            if (movie.rating >= minRating) {
                cout << "제목: " << movie.title << ", 평점: " << movie.rating << "\n";
            }
        }
    }
};

int main() {
    MovieManager manager;

    cout << "1. 영화 목록 출력\n";
    manager.printMovies();

    cout << "\n2. 영화 검색 (예: Interstellar)\n";
    manager.findMovie("Interstellar");

    cout << "\n3. 평점 기준 정렬 및 출력\n";
    RatingSorter sorter;
    manager.processMovies(sorter);

    cout << "\n4. 평점 8.5 이상인 영화 필터링 및 출력\n";
    RatingFilter filter(8.5);
    manager.processMovies(filter);

    return 0;
}

 

 

3. FIX

  • 도전X도전 실습 수정
// 제공되는 코드에 foreach를 동작시키기 위해 필요한 함수를 추가
#include <iostream>
#include <vector>
using namespace std;

template <typename T>
class Array {
    T data[100];
    int size;
public:
    Array() : size(0) {}

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

    void remove() {
        if (size > 0)
            size--;
    }

    void print() {
        vector <T> temp(data, data + size);
        for (T item : temp) { // Range-based for loop
            cout << item << " ";
        }
        cout << endl;
    }
    // 시작 위치 (첫 번째 원소의 주소)
    T* begin() { return &data[0]; }
    // 끝 위치 (마지막 원소 다음의 주소)
    T* end() { return &data[size]; }
};

int main() {
    Array<int> arr; // 정수형 배열 생성
    arr.add(10);
    arr.add(20);
    arr.add(30);
    arr.print();

    arr.remove();
    arr.print();

    for (auto n : arr) { // Range-based for loop
        cout<<n << endl;
    }
    return 0;
}

 

 

 

begin()과 end()만 있으면 컨테이너가 아니어도 range-based for 사용 가능!

range-based for 문은 내부적으로 begin()과 end()를 호출하여 시작과 끝 반복자를 얻고, 반복자를 증가시키며 순회.
포인터는 반복자 연산을 지원하므로 배열의 주소를 반환하면 사용자 정의 클래스도 range-based for를 사용할 수 있다.

 

 

 

4. 참고

https://wn42.tistory.com/110

 

[C++] 오버로딩 (Overloading) - 2. 연산자

[C++] 오버로딩 (Overloading) - 1.함수, 생성자 오버로딩 (overloading) 같은 이름의 메소드(method) 또는 생성자를 매개변수의 개수나 타입을 다르게 지정함으로써 2개 이상 정의하는 것 함수 오버로딩 함

wn42.tistory.com

https://modoocode.com/230

 

씹어먹는 C ++ - <11. C++ 에서 예외 처리>

모두의 코드 씹어먹는 C ++ - <11. C++ 에서 예외 처리> 작성일 : 2018-09-17 이 글은 90244 번 읽혔습니다. 안녕하세요 여러분! 오래 간만에 인사 드립니다. 이번 강좌에서는 C++ 에서 예외 처리를 어떠한

modoocode.com

https://blockdmask.tistory.com/319

 

[C++] range based for, 범위기반 for 반복문에 대해서.

안녕하십니까. BlockDMask입니다.오늘 공부할 내용은 C++11에 추가된 범위기반 반복문 range based for문 입니다. 혁명이죠. 놀랍죠. 하지만 범위기반 for문이 완전히 for문을 대체하지 못합니다. why? 왜때

blockdmask.tistory.com

https://www.youtube.com/watch?v=YnhNgMJvQh0&t=2s

https://cppinsights.io/

 

C++ Insights

C++ Insights - See your source code with the eyes of a compiler.

cppinsights.io

https://en.cppreference.com/w/cpp/language/range-for.html

 

Range-based for loop (since C++11) - cppreference.com

Executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container. [edit] Syntax attr (optional) for ( init-statement (optional) item-declaration

en.cppreference.com

 

'내배캠Unreal_TIL > C++' 카테고리의 다른 글

[C++] STL 총정리  (0) 2025.12.18
[TIL] 2025-12-18 | 과제3 구현 및 vector 동작 원리 이해  (0) 2025.12.18
[TIL] 2025-12-16 | C++ STL, vector, map, sort(), find(), Iterator  (2) 2025.12.16
[TIL] 2025-12-15 | C++ 스마트 포인터, 템플릿  (0) 2025.12.15
[TIL] 2025-12-12 | 과제1 구현 및 입력 실패 처리, C++ 힙메모리  (0) 2025.12.12
'내배캠Unreal_TIL/C++' 카테고리의 다른 글
  • [C++] STL 총정리
  • [TIL] 2025-12-18 | 과제3 구현 및 vector 동작 원리 이해
  • [TIL] 2025-12-16 | C++ STL, vector, map, sort(), find(), Iterator
  • [TIL] 2025-12-15 | C++ 스마트 포인터, 템플릿
윤윤씨
윤윤씨
🎮 내일배움캠프 Unreal 7기
  • 윤윤씨
    컴퓨터온열맛사지
    윤윤씨
  • 전체
    오늘
    어제
    • 분류 전체보기 (62)
      • 내배캠Unreal_TIL (62)
        • C++ (23)
        • UE (31)
        • 팀프로젝트 (7)
      • etc (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
    • Solved.ac
    • YouTube
  • 태그

    스테이트머신
    챌린지
    코드카타
    gas
    STL
    프로그래머스
    오토마타
    디자인패턴
    ta
    머티리얼
    언리얼과제
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.6
윤윤씨
[TIL] 2025-12-17 | C++ 예외 처리, 연산자 오버로드, 객체지향적 설계
상단으로

티스토리툴바