[C++ 기초] template, 템플릿 클래스, STL 자료구조 개론

라멘커비·2024년 1월 9일
0

CPP 입문

목록 보기
19/25
post-thumbnail

template 템플릿

🧁템플릿 개요

  • cout은 숫자도 되고 포인터도 되고 다 된다. 오버로딩이 되어 있는 것.
std::cout.operator<<(1);
std::cout.operator<<("fsdfsdf");
std::cout.operator<<(true);

자료형마다 함수를 새로 만들어야 하는 것이 아니다.

단 한 번만 함수를 만들어서 여러 가지로 사용할 수 있는 문법이 템플릿 문법이다.

🧁템플릿 사용 방법 및 예시

자료형을 마치 변수처럼 사용하는 문법이다.

template<typename 이름>
  • 템플릿은 컴파일러가 코드를 대신 만들어 사용하는 문법이다.
    컴파일러가 입력된 자료형으로 함수를 대신 만들어주는 것이다.
    어떤 자료형이라는 것을 알고 알아서 해주는 것인데 이것을 템플릿 인자추론이라고 한다.

  • 템플릿 함수를 사용할 때는 눈에 보이지 않아도 자료형이 붙어있다.

Print(BoolPtr);
Print<bool*>(BoolPtr);
  • 예시
#include <iostream>

template<typename Type>
void Print(Type _Value) {
    std::cout << *_Value << std::endl;
}

int main()
{   
    int Value = 10;
    int* IntPtr = &Value;

    bool Value2 = true;
    bool* BoolPtr = &Value2;

    Print(IntPtr);
    Print(BoolPtr);
    Print<bool*>(BoolPtr);	// 정식 호출 방법, 윗줄과 같은 코드.
    return 0;
}

템플릿은 사용자가 다양한 자료형으로 사용하면 컴파일러가 컴파일하면서 아래와 같이 함수들을 만들어 내는 문법이다.

🧁템플릿 특수화

그냥 오버로딩임.
이미 같은 이름의 템플릿 함수가 있으면 그게 템플릿 특수화다.

char* 자료형을 집어 넣었을 때는 출력하는 코드를 다르게 해야하므로 오버로딩해서 새로 만들었다.
예외를 두는 문법이라 선생님은 선호하시지 않음.

#include <iostream>

template<typename Type>
void Print(Type _Value) {
    std::cout << *_Value << std::endl;
}
void Print(const char* _Value) {
    std::cout << _Value << std::endl;
}

int main()
{   
    int Value = 10;
    int* IntPtr = &Value;

    bool Value2 = true;
    bool* BoolPtr = &Value2;

    Print("ddd");
    Print(IntPtr);
    Print(BoolPtr);
    Print<bool*>(BoolPtr);
    return 0;
}

🧁템플릿 클래스

사용 모습

template<typename MemberType>
class TemplateClass {
public:
    MemberType Value;
};

int main()
{   
    TemplateClass<int> NewType = TemplateClass<int>();
    NewType.Value = 20;
    std::cout << NewType.Value << std::endl;
    return 0;
}

1. 인자추론이 안 된다.

클래스의 크기는 내부 멤버 변수의 크기에 의해서 결정되는데 인자를 명시해주지 않으면 클래스의 크기를 알 수 없게 되기 때문이다.

template<typename MemberType>
class TemplateClass {
public:
    MemberType Value;
};

int main()
{   
    TemplateClass<int> NewType;
    return 0;
} 

2. 템플릿 클래스는 헤더와 cpp파일 분할이 불가능하다.

모든 내용을 헤더 안에 구현해야 한다.
인자추론이 안되기 때문이다.

3. 대입 안 된다.

템플릿 클래스간의 호환은 완전히 동일한 템플릿 클래스만 가능하다.

TemplateClass<int> != TemplateClass<bool>
TemplateClass<int> == TemplateClass<int

(당연함)

STD

  • std : C++ 스탠다드 라이브러리
    C++ 만든 사람들이 새롭게 C++을 시작하는 사람들이 편하게 프로그래밍 할 수 있도록 미리 함수나 클래스를 다 만들어 둔 라이브러리다.

(거의 모든 분야의 편리하거나 사용해야 하는 클래스 등을 OS나 C++에서 다 만들어 뒀다. 없다면 깃허브에 고수들이 다 만들어놨음. 검색 능력과 언어 능력이 있으면 다 활용 가능.)

  • stl이건 다른 분야건 스탠다드 라이브러리는 std:: 네임스페이스를 해놨다.
    std::array std::vector ...
    stl 중에 배열은 array다. #include <array>
// vector 사용 예시
std::vector<int> ArrVector = std::vector<int>(5); 
  • std 라이브러리 중에 템플릿을 쓰는 것들을 stl이라고 한다. 자료구조가 유명해서 그렇지 템플릿 관련된 건 다 stl이라고 부른다.

인터페이스?

클래스와 함수 코드의 사용 방식을 말한다.

자료구조 면접 단골 3대장

  • vector
  • map
  • list

그 외에

  • string
  • queue
  • stack

🧁자료구조 개론

자료구조란 특정 객체나 오브젝트의 메모리의 할당, 삭제, 탐색 등을 하는 방법을 모두 아우르는 말이다.

자료구조를 보통 컨테이너라고 부른다.
컨테이너에는 3가지 분류가 있다.

  • 시퀀스 컨테이너
    • vector, list
  • 연관 컨테이너
    • map
  • 어뎁터 컨테이너
    • string, stack, queue

자료 추가하는 법, 삭제하는 법, 찾는 법 => 멤버 함수

시퀀스 컨테이너

자료를 순서대로 넣었을 때 자료의 순서가 바뀌지 않으면 시퀀스 컨테이너이다.

연관 컨테이너

자료를 순서대로 넣었을 때 자료의 순서가 바뀌면 연관 컨테이너이다.
그렇다고 정렬해준다고 연관 컨테이너라는 것은 아니다. 순서가 바뀌기만 하면 모두 연관 컨테이너이다.

어댑터 컨테이너

https://tcpschool.com/cpp/cpp_container_adapter

과제

🧁240109_ArrayResize

할 일)
ConsoleEngine도 같이 옮겨놓기
"240109_ArrayResize" 이름의 프로젝트 만들기
1. 결과가 의도대로 나오지 않는 이유를 알아내기
2. 의도대로(아래와 같이) 출력되도록 만들기
기존에 있는 존재하는 값을 보존하면서 확장할 수 있게 만들기.
선생님이 테스트 값을 변경해도 돌아가야 한다.

ex)
0
1
2
3
4
???
???
???
???
???

1. 이유

Resize함수에서 기존 배열을 delete한 후에 새로 동적 할당을 해주는 것까지만 기능하기 때문에 값이 초기화 되어있지 않다. 원래 배열에 있던 값들을 옮겨주는 기능을 추가해야 한다.

2. 다시 만들기

처음에 무조건 NulValue만큼의 데이터를 옮기도록 짜서 만약 원래 크기보다 작게 ReSize한다면 오류가 났다. 선생님의 풀이를 본 뒤 smallSize라는 변수에 두 배열 중 더 작은 배열 크기를 넣고 옮기도록 바꿨다.

#include <iostream>
#include <ConsoleEngine/EngineDebug.h>

class IntArray
{
    // private: 디폴트 접근제한 지정자
public:
    // 디폴트 생성자
    IntArray(int _Size)
    {
        ReSize(_Size);
    }

    // 디폴트 복사 생성자
    IntArray(const IntArray& _Other)
    {
        Copy(_Other);
    }
    // 디폴트 소멸자
    ~IntArray()
    {
        Release();
    }
    // 디폴트 대입연산자
    void operator=(const IntArray& _Other)
    {
        Copy(_Other);
    }

    int& operator[](int _Count)
    {
        return ArrPtr[_Count];
    }

    int Num()
    {
        return NumValue;
    }

    void Copy(const IntArray& _Other)
    {
        NumValue = _Other.NumValue;

        // 깊은 복사를 해줘야 합니다.
        ReSize(NumValue);
        for (int i = 0; i < NumValue; i++)
        {
            ArrPtr[i] = _Other.ArrPtr[i];
        }
    }

    void ReSize(int _Size)
    {
        if (0 >= _Size)
        {
            MsgBoxAssert("배열의 크기가 0일수 없습니다");
        }

        // ArrPtr이 nullptr이 아닌 경우에
        if (nullptr != ArrPtr)
        {
            // Release하기 전에 기존 배열 복사해두기
            int* Temp = ArrPtr;
            // Temp   = [0][1][2][3][4]
            // Arrptr = [0][1][2][3][4]
            
            // 새로 만들 배열
            ArrPtr = new int[_Size]; 
            // Temp   = [0][1][2][3][4]
            // ArrPtr = [?][?][?][?][?][?][?][?][?][?]

            int smallSize = NumValue <= _Size ? NumValue : _Size;

            for (int i = 0; i < smallSize; i++) {
                ArrPtr[i] = Temp[i];
            }            
            if (nullptr != Temp) {
                delete Temp;
                Temp = nullptr;
            }
        }
        else {
            // Arrptr이 null인 경우 만들기만 하면 됨
            ArrPtr = new int[_Size];
        }

        NumValue = _Size;
    }

    void Release()
    {
        if (nullptr != ArrPtr)
        {
            delete[] ArrPtr;
            ArrPtr = nullptr;
        }
    }

private:
    int NumValue = 0;
    int* ArrPtr = nullptr;
};


int main()
{
    LeakCheck;

    IntArray NewArray = IntArray(5);

    for (int i = 0; i < NewArray.Num(); i++)
    {
        NewArray[i] = i;
    }


    // 리사이즈 값은 얼마든지 변경될 수 있다.
    NewArray.ReSize(10);
    //NewArray.ReSize(3); // 작게도 가능
    // ?는 무슨값이 들어가 있어도 괜찮다.
    // [0][1][2][3][4][?][?][?][?][?]

    for (int i = 0; i < NewArray.Num(); i++)
    {
        std::cout << NewArray[i] << std::endl;
    }
}

과제 제출 깃허브

profile
일단 시작해보자

0개의 댓글

관련 채용 정보