개발을 뚝딱뚝딱/매일매일 개발일지

[C++] 구조체, typedef, templete

공돌이J 2022. 1. 7. 22:26

자바로 프로그래밍을 시작했지만, 파이썬을 4년 넘게 하면서 파이썬 스타일의 코딩에 너무 익숙해져 버리는 바람에 컴파일 언어가 너무 어려워져버렸습니다. 그래서 이번에 C++을 공부하면서 파이썬과 다른 내용들, 헷갈리거나 생소한 개념들을 정리하고자 합니다. 자체적으로 교차검증을 하긴 했지만 틀린 내용이 있다면 댓글로 알려주시면 수정하도록 하겠습니다.

1. 구조체(struct)

여러 자료형을 저장할 수 있는 자료형입니다. 객체지향 프로그래밍의 클래스와 비슷하지만, 메소드가 존재하지 않고 멤버변수로만 이루어져 있습니다. 한번에 여러 개의 값을 담을 수 있다는 장점이 있기 때문에 함수의 입력값과 반환값이 여러 개일 때 사용하기 용이합니다.

파이썬의 딕셔너리와 비교하자면 조금 더 자료형과 구조가 잡혀있는 형태라고 생각하면 좋을 것 같습니다.

  • 구조체의 선언

구조체의 선언 방법은 아래와 같습니다.

struct MyFriend{
	std::string name;
	int age
};

구조체 선언의 마지막에 세미콜론을 작성해야 합니다.

  • 멤버 변수 초기화와 접근

구조체를 초기화하기 위해서는 초기화 목록을 사용하는 방법과 멤버변수별로 값을 초기화 하는 방법이 있습니다. 초기화 목록을 사용하지 않고 구조체를 선언하면 멤버변수는 쓰레기값/기본값이 저장되기 때문에 해당 구조체를 제대로 사용하기 위해서는 반드시 초기화를 해주어야 합니다.

구조체의 멤버변수에 접근하기 위해서는 . 연산자를 사용합니다.

//초기화 목록을 이용한 구조체 초기화
MyFriend minsu = {"민수", 21};
std::cout << minsu.name << std::endl;

// 멤버변수 별 초기화
MyFriend chulsu;
chulsu.name = "철수";
chulsu.age = 20;
std::cout << chulsu.name << std::endl;

아래와 같이 구조체 안의 멤버변수로 구조체를 참조할 수 있습니다.

struct ClassMate{
        MyFriend mf;
        int grade;
    };
    
ClassMate cm1 = {minsu, 1};
ClassMate cm2;
cm2.mf = chulsu;
cm2.grade = 2;

2. typedef

자료형의 별칭을 지정할 수 있는 예약어입니다. 이미 정의된 자료형과 사용자 정의 자료형, 또는 포인터의 별칭을 지정하여 가독성을 높히거나 사용자의 편의를 높이기 위해 사용됩니다.

  • 사용법

typedef를 사용할 때는 typedef 자료형 별칭; 과 같은 형태로 작성해야 합니다. 관습적으로 별칭 뒤에는 _t를 붙혀줍니다.

typedef int age_t;

// 아래의 두 변수는 같은 int 자료형입니다.
int age1;
age_t age2;

C++ 11부터는 아래와 같이 선언할 수도 있습니다.

using age_t = int
  • 활용

typedef는 다양한 경우에 활용할 수 있습니다. 먼저 다음의 예제를 보겠습니다.

// 1번
int GradeTest();
// 2번
typedef int testScore_t;
testScore_t GradeTest()

1번과 2번 중 어떤 코드가 더 프로그램을 이해하는데 좋을까요? 1번 코드의 경우 반환하는 값이 합격/불합격을 나타내는 1/0인지, 점수를 반환하는지 직관적으로 이해하기 어렵습니다. 하지만 2번 코드의 경우 반환하는 값이 점수를 나타낸다고 별도의 주석이나 설명 없이도 이해할 수 있습니다.

두 번째로는 복잡한 자료형을 간단하게 표현할 때 사용합니다. 아래의 자료형은 배우 복잡하지만, typedef로 별칭을 지어 직관적이고 간단하게 나타낼 수 있습니다.

// 1번
std::vector<std::pair<std::string, int>> pairlist; 

bool hasDuplicates(std::vector<std::pair<std::string, int> > pairlist) { 
// some code here 
}

// 2번
typedef std::vector<std::pair<std::string, int>> pairlist_t; // make pairlist_t an alias for this crazy type 
pairlist_t pairlist; // instantiate a pairlist_t 
bool hasDuplicates(pairlist_t pairlist) // use pairlist_t in a function parameter { // some code here }

잠깐 보더라도 1번 코드보다는 2번 코드가 훨씬 가독성이 좋은 것을 알 수 있습니다.

마지막으로 플랫폼에 따라 자료형에 할당되는 바이트가 다를 수 있습니다. 예를 들어 정수 자료형의 경우, 컴파일러나 플랫폼에 따라 2바이트 혹은 4바이트로 설정될 수 있는데 아래와 같이 선언하게 된다면 overflow 등의 문제를 미리 방지할 수 있습니다.

#ifdef INT_2_BYTES 
typedef char int8_t; 
typedef int int16_t; 
typedef long int32_t; 
#else 
typedef char int8_t; 
typedef short int16_t; 
typedef int int32_t; 
#endif

3. template

함수나 클래스에서 다양한 자료형을 입력받아야할 때 각각의 자료형에 대해서 함수를 오버로딩하지 않고도 매개변수의 타입을 다양하게 받을 수 있도록 하는 기능입니다. 파이썬의 경우에는 매개변수의 타입을 지정하지 않기 때문에 필요성을 느끼지 못했지만, 자바나 C++같은 언어에서는 변수의 자료형을 반드시 선언해 주어야 하기때문에 매우 유용한 기능입니다.

  • 탬플릿의 선언

사용하고자 하는 함수나 클래스 위에 선언하여 사용합니다. 이때 typename 대신 class를 사용할 수 있습니다.

template <typename T>
float add(T a, T b){
    return a + b;
}

template<class T>
float add_c(T a, T b){
	  return a + b;
}

int main(){
std::cout << add(1, 4) << " " << add(1.3, 4.2);
std::cout << add_c(1, 4) << " " << add_c(1.3, 4.2);
}

클래스의 메소드에서 사용하고자 한다면 클래스 위에 선언해 주면 됩니다. 단, 클래스 외부에서 메소드를 정의하게 된다면 아래와 같이 정의하는 함수 위에 다시한번 templete을 작성해 주어야 합니다.

template <typename T>
class Profile{

public:
    std::string name;
    T age;
    T height;
    Profile(std::string name, T age, T height):name(name), age(age), height(height){

    }

    void setAge(T age){
        this->age = age;
    }
    void setHeight(T h);
};

template <typename T>
void Profile<T>::setHeight(T h) {
    height = h;
}

int main(){

    Profile<int> profile1("Minsu", 10, 180);
    Profile<float> profile2("Chulsu", 13.1, 158.1);

    std::cout<<profile1.name << " " << profile1.age << " " << profile1.height << std::endl;
    std::cout<<profile2.name << " " << profile2.age << " " << profile2.height << std::endl;

    profile1.setAge(13);
    profile1.setHeight(120);
    profile2.setAge(22);
    profile2.setHeight(190.9);

    std::cout<<profile1.name << " " << profile1.age << " " << profile1.height << std::endl;
    std::cout<<profile2.name << " " << profile2.age << " " << profile2.height << std::endl;

    return 0;
}

 

reference

구조체

https://boycoding.tistory.com/183

typedef

https://dojang.io/mod/page/view.php?id=409

template

https://blockdmask.tistory.com/43

https://wikidocs.net/433

https://boycoding.tistory.com/182?category=1008283

'개발을 뚝딱뚝딱 > 매일매일 개발일지' 카테고리의 다른 글

npm install --save 옵션에 대하여  (0) 2018.01.11
18.01.08 개발일지  (0) 2018.01.08