Post

2026-02-27 TIL (5일차)

2026-02-27 TIL (5일차)

Unreal 강의

  1. 상태 머신 설계하는 방법 ● 오브젝트가 가질 수 있는 모든 상태 정리 (대기,걷기,달리기 등등) ● 상태1 -> 상태2 처럼 현재 상태에서 다른 상태로 변경 될 때마다 모든 조건 정리

C++ 공부

  1. 함수 포인터

    ● 변수 포인터는 메모리 절약과 효율인데 함수 포인터는 결정의 유연성(코드의 설계) 을 위한 것입니다.

    구현되는 원리는 포인터랑 같다!
    포인터라는 상자 안에 ‘주소’를 담는다는 점은 변하지 않아요. 다만, 그 주소가 데이터를 가리키느냐, 함수를 가리키느냐의 차이일 뿐 차이점: 가리키는 공간이 다름.
    ( 변수 포인터 - 스택,힙,데이터 , 함수 포인터 - 코드[ Code / Text ] 영역)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    int foo()
    {
     return 5;
    }
    
    int goo()
    {
     return 6;
    }
    
    int main()
    {
     int (*fcnPtr)() = foo; // fcnPtr points to function foo
     fcnPtr = goo; // fcnPtr now points to function goo
        return 0;
    }
    

    C++는 기본 자료형과 달리 필요할 경우 함수를 함수 포인터로 암묵적으로 변환하므로 주소 연산자 &를 사용할 필요가 없다.
    이유: 배열이랑 비슷한 개념이다.
    ●함수는 코드 영역에 저장된 명령어들의 집합 이기 때문에 함수이름이 시작 주소(진입점 주소)이다.
    함수는 시작점부터 실행해야 하는 존재다. 그래서 이름 자체가 곧 시작 주소로 통하도록 설계되었다!

    활용 예시
    ● 함수 누구를 부를지를 실행 중에 결정하기 위해서 (런타임 결정)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    void Attack() 
    {
     std::cout << "기본 공격" << std::endl;
    }
    
    void Defense() 
    {
     std::cout << "기본 방어" << std::endl;
    }
    
    int main()
    {
     void (*ptr)() = nullptr;
     int input;
     std::cin >> input;
    
     if (input == 1) 
     {
         ptr = Attack;
     }
     else if (input == 2) 
     {
         ptr = Defense;
     }
        
     if (ptr != nullptr) //만약 이 조건문이 없으면 input값이 1,2가 아니면 nullptr에 있는 함수를 실행을 시켜서 오류가 생김
     {
         ptr();
     }
    }
    

    ● 함수를 부품처럼 갈아 끼우기 (전략패턴)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    bool Better(int a, int b) 
    {   
        return a > b;
    }
    
    bool Worese(int a, int b) 
    {
        return a < b; 
    }
    
    void Sort(int* arr, int size, bool (*compare)(int, int)) 
    //배열을 포인터로 받고 , 0부터 size-1만큼 정렬한다, 무슨 함수를 포인터로 받고 넘길꺼냐? 이러면 bool 함수+매개변수 2개인 함수는 다 가능
    {
        for (int i = 0; i < size - 1; i++) 
        {
            for (int j = i + 1; j < size; j++) 
            {
                if (compare(arr[i], arr[j]))//저장되어있는 함수의 주소로가서 실행함 
                { 
                    std::swap(arr[i], arr[j]);
                }
            }
        }
    }
    

    ● 콜백, Callback

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    void OnCompleteNotify() 
    {
        std::cout << "팝업" << std::endl; 
    }
    void OnCompleteLogin() 
    {
        std::cout << "로그인" << std::endl;
    }
    
    void DownloadFile(void (*callback)()) 
    { 
        std::cout << "다운로드 중..." << std::endl;
        callback(); //"아까 할당 받은 주소로 다시 가 
        std::cout << "다운로드 중2..." << std::endl;
    }
    int main()
    {
        DownloadFile(OnCompleteNotify);
        //OnCompleteNotify라는 이름(주소)을 복사해서 callback이라는 매개변수에 저장
        //DownloadFile을 실행 시키는데 callback 실행 -> 안에는 OnCompleteNotify저장되어있음
        // OnCompleteNotify가 끝나면 **다시 DownloadFile** 로 돌아온다. (당연히 자신위치 뒤 부터 실행시킨다.)
    }
    
  2. Dangling Pointer

    ★ 하기전에 알면 좋은 지식 동적할당
    ● int *pi = new int; ->여기서 포인터는 주소를 받아야하는데 new int 어디에 주소가 있는거야?
    new라는 연산자 자체가 메모리를 빌린 뒤, 그 시작 주소를 결과값으로 돌려주는 기능
    (쉽게 설명하면 함수 포인터, 배열 처럼 이름 자체로만 쓰면 시작 주소를 준다는 의미, 즉 할당받을 시작주소를 이미 들고있다는거임)
    ● 배열을 동적할당 받으면 delete[]로 빌린 size만큼 삭제시키던데 2차원배열도 그냥 delete[]] 이렇게 하면 안돼?
    한 줄이 몇 칸인지 몰라서 한 줄을 뛰어넘을 때 얼마나 지워야하는지 몰라서 안된다.
    그래서 2차원 배열 기준은 한줄 자체를 지우고 또 다시 한줄 지우는 형태로 해야한다.

    정의: 이미 해제된 메모리 주소를 여전히 가리키고 있는 포인터를 말합니다. 간단하게 설명하면 값이 존재하지 않는 주소에 가겠다는 뜻입니다.

    1. 메모리 해제 후 포인터를 초기화하지 않았을 때. 특히 동적 할당한 경우
    2. 지역 변수의 주소를 반환했을 때
  3. 클래스
    ●클래스와 구조체의 차이 정보은닉인 캡슐화의 차이
    (클래스는 접근 제어 지시자에 따라 자기 내부 변수를 못건들게 한다. 대표적으로 hp를 외부에서 직접 못건들게하고 함수를 통해서만 접근해 상호작용하게 한다.)
    (private를 외부에서 접근하는 방법: 생성자로 접근, public에 Set 함수를 구현해서 값을 넣는다, friend 키워드 사용)

    ● 정보은닉, 캘슐화 하는 이유
    잘못된 값을 저장되지 않도록 하기 위해서 사용합니다.

    ● 클래스를 동적할당을 받는 이유

    1. 생명주기가 길어 할 때 사용 -> 일반적인 변수로 선언하면 함수 구문이 끝나면 변수가 사라지기 때문입니다. (캐릭터,몬스터 등등)
    2. 다형성을 구현 할 때 (부모인 몬스터 클래스 하나로 여러 몬스터들을 할당받아 관리도 가능하기 때문에)

    ● const 함수의 위치에 따른 역할차이

    위치명칭사용 가능 범위주요 목적
    앞 (const int* F())반환 타입 상수화모든 함수돌려받은 값을 수정하지 못하게 함
    끝 (void F() const)멤버 함수 상수화클래스 멤버 함수만함수 안에서 멤버 변수를 수정하지 못하게 함

    ● 생성자를 구현할 때 이니셜라이저 vs 대입의 차이
    이니셜라이저: 객체가 메모리에 생성되는 순간에 값을 채워 넣습니다.
    대입: 객체가 메모리에 이미 생성된 후(기본값으로), 그 안에 있던 값을 지우고 새 값으로 덮어씁니다.
    ★ 이니셜라이저가 성능에 약간의 이점이 있다.

  4. inline 함수
    inline 함수는 배열이나 함수 포인터를 타고 멀리 점프하지 말고, 그 자리에 코드를 복사해서 붙여넣어라고 컴파일러에게 부탁하는 명령어
    추천: 1~3줄 정도의 아주 짧은 함수 (예: Getter/Setter, 단순 계산 함수).

C/C++ 강의 (02-27일 강의 전방선언부터 중요한 내용)

  1. 전방선언
    일단 이 함수 있으니까 여기서 없다고 징징거리지마라 라고 미리 알려주는 느낌
    원형을 그대로 적어준다 - 타입 이름 (매개변수)
This post is licensed under CC BY 4.0 by the author.