Unreal5 공부/TIL

2026/03/20 TIL

anna59 2026. 3. 20. 21:08

 

오늘의 목표

  • 아침 코드카타
  • 2-3 숙제
  • 2-4 강의 수강
  • 2-4 강의 복습
  • 2-4 숙제
  • 2-5 숙제
  • 챕터 2 과제

추가목표: github 기초


 

1. 아침 코드카타(완료)

2. 2-3 숙제 (완료)

3. 2-4 강의 수강 (완료)

4. 2-4 강의 복습 (완료)

5. 2-4 숙제 (완료)

 

 

 

오늘의 배운 점

객체 지향적 설계 방법.

응집도 높게, 결합도 낮게, SOLID 원칙을 지켜서 class를 정의하고 사용한다. 

 

 

자세히 공부했던 부분

 

#include <iostream>
#include <memory>

using namespace std;

// 공통 인터페이스 정의
class Engine {
public:
	virtual void start() = 0;
    virtual ~Engine() = default;
};

// DieselEngine 구현
class DieselEngine : public Engine {
public:
	void start() {
    	cout << "Diesel Engine started" << endl;
    }
};

// 새로운 ElectricEngine 구현
class ElectricEngine : public Engine {
public:
	void start() {
    	cout << "Electric Engine started silently" << endl;
    }
};

// Car 클래스는 Engine 인터페이스에만 의존
class Car {
private:
	unique_ptr<engine> engine;
public:
	car(uniqe_ptr<Engine> eng) : engine(move(eng)) {} // unique_ptr의 소유권을 옮긴다.
    
    void startCar() {
    	engine->start();
        cout << "Car started" << endl;
    }
};

int main() {
	// DieselEngine을 사용하는 경우
    auto dieselEngine = make_unique<DieselEngine>();
    Car dieselCar(move(dieselEngine)); // car 생성자는 Engine 타입의 unique_pointer를 받음
    dieselCar.startCar();
    
    // ElectricEngine을 사용하는 경우
    auto electricEngine = make_unique<ElectricEngine>();
    Car electricCar(move(electricEngine)); // car 생성자는 Engine 타입의 unique_pointer를 받음
    electricCar.startCar();
    
    return 0;
}

 

<Q1>해당 코드에서 그냥 diselEngine의 클래스를 바로 사용하지 않고 스마트 포인터를 사용한 이유가 뭘까?

 

'스마트 포인터' 자체를 사용한 이유는 일단 메모리 관리를 유용하게 하기 위해서고, Car에서 스마트포인터를 받아서 사용한 이유는 동적으로 객체를 받아 사용하기 위함이다. 결국 다형성을 위한 것.

 

1. 부모 클래스인 Engine 클래스에서 추상화된 start()를 자식 클래스인 DieselEngine과 ElectricEngine에서 각각 재정의

2. unique_pointer를 통해서 DieselEngine 혹은 ElectricEngine 개체를 생성

3. Car의 생성자에 해당 포인터를 넘기면 DieselEngine 혹은 ElectricEngine의 개체가 Car의 Engine 변수에 저장된다.

4. Car의 startCar() 에서 Engine 변수->start()를 함으로서 자식 클래스에서 정의된 각각의 start()를 불러오게 된다.

 

아직 이 흐름이 익숙하지 않은 것 같으니 여러 번 다시 코드를 받아써볼 것.

 

 

class Printer{
public:
	virtual void print() = 0;
};

class Scanner {
public:
	virtual void scan() = 0;
};

class BasicPrinter : public Printer {
public:
	void print() override {
    	// 문서 출력
    }
}

class MultiFuntionDevice {
private:
	Printer* printer;
    Scanner* scanner;
    
public:
	MultiFuntionDevice(Printer* p, Scanner* s) : printer(p), scanner(s)
    
    void print() {
    	if (printer) printer->print();
    }
    
    void scan() {
    	if (scanner) scanner->scan();
    }
};

 

<Q2> 왜 해당 코드의 BasicPrinter에서 override를 사용하고 MultiFuntionDevice에서는 사용하지 않는걸까?

A. BasicPrinter는 직접적으로 Printer를 상속받는 파생 클래스이기 때문에, Printer의 순수 가상 함수인 print()를 재정의한다고 컴파일러에게 명확하게 명시해 주는 역할로서 override가 사용된다.

 

MultiFunctionDevice에서는 override를 사용하지 않는 이유:

단순하게 외부에서 포인터를 통해 Printer나 Scanner 개체를 받아서 쓸 뿐, 상속 관계가 없기 때문이다.

 

MultiFunctionDevice에서 사용할 변수와 함수들을 필요에 맞게 조각조각 나눠 정의한 뒤 한번에 MultiFunctionDevice를 통해 정리해서 사용하는 방식이라고 이해하면 될 것 같다.

 

더 공부해볼 것

객체 지향적 코드와 다형성 코드가 아직 익숙하지 않은 것 같으니 여러 번 다시 직접 받아 써볼것!

특히 다형성 내용 복습할것