typedef와 typename

typedef

타입의 새로운 별칭을 정의하는 키워드

typedef struct 구조체이름 {
    자료형 멤버이름;
} 구조체별칭;

typedef는 클래스 안에서 타입의 새로운 별칭을 지을 수 있다.

class MyTypeClass
    {
    public:
        typedef int Type1;
    };
    int main()
    {
        MyTypeClass a;
        MyTypeClass::Type1 b;
        return 0;
    }

a는 MyTypeClass의 객체, b는 int 변수이다.

 class MyTypeClass
    {
    public:
        typedef int Type1;
    private:
        typedef double Type2;
    };
    int main()
    {
        MyTypeClass a;
        MyTypeClass::Type1 b;
        MyTypeClass::Type2 c;  //에러
        return 0;
    }

타입선언이 private로 선언되어 있으면 사용하는 것도 내부적으로 사용해야함.
->typedef은 클래스 안에서도 타입의 별칭을 만들 수 있을 뿐 아니라 외부접근 제한 까지 영향을 받는다.

템플릿 파라미터로 받은 데이터 타입이 필요할 때

#include <iostream>

    template<typename T>
    class MyTempClass
    {
    public:
        typedef T TempType;
    };
    int main()
    {
        MyTempClass<int> a;
        MyTempClass<int>::TempType b;
        MyTempClass<double> c;
        MyTempClass<double>::TempType d;
        return 0;
    }

타입 안 타입의 객체를 호출 할 수 있다. 이렇게 템플릿 매개변수에 종속된 것을 의존 이름(dependent name) 이라고 한다. 클래스안에 중첩된 경우가 있는데 중첩 의존 이름(nested dependent name) 이라고 한다.

ex) STL의 반복자 (C++ Standard Library 예제)
컨테이너를 받아서 처음부터 끝까지 루프 돌며 모든 원소를 출력하는 코드.

template <class T>
    inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
    {
        typename T::const_iterator pos;
          // typename 키워드는 다음에 언급합니다

        std::cout << optcstr;
        for (pos=coll.begin(); pos!=coll.end(); ++pos) {
            std::cout << *pos << ' ';
        }
        std::cout << std::endl;
    }

컨테이너가 벡터, 리스트, 데크 인지도 알 수 없지만 컨테이너 원소가 int, double, char 형인지 도 알 수 없다. 하지만 각 컨테이너 안에 상수반복자를 typedef 키워드로 const_iterator 라고 정의 했기에 어떤 원소를 담은 어떤 컨테이너가 들어와도 함수가 동작 할 수 있다.

+typedef 이름 관례: typedef로 새로운 이름을 만들 떄 원래 그 멤버 이름과 똑같이 짓는 것이 관례이다.

typedef 장점

  1. 입력과 읽기가 편하다.
  2. 의사 전달이 가능하다.
    ex)
int	x;
int	y;
y = x * 3; //문제는 없다.

typedef int Inches;
typedef int Dollars;
Inches x;
Dollars y;
y = x * 3; //의사 전달이 쉽다.
  1. 호환성을 높여준다.
    -플랫폼에 따라서 이름을 달리 써야 하는 경우나 호환이 안되는 이름에 대해서 typedef를 사용하면 새로운 플랫폼으로 옮기는 작업이 간편해진다.
    ex)
#if defined USING_COMPILER_A
      typedef __int32 Int32;
      typedef __int64 Int64;
    #elif deined USING_COMPILER_B
      typedef int Int32;
      typedef long long Int64;
    #endif
  1. 유연성이 생긴다.
    -typedef 된 이름이 한 곳에서 바꾸는 것이 코드 전체를 찾아서 이름이 쓰인 곳마다 바꾸는 것보다 훨씬 간단하다.
    5.특성화를 가능하게 한다. //??
    -특성 이디엄(traits idiom)을 이용하면 정보에 타입을 정해줄 수 있다. 표준 컨테이너나 알고리즘을 커스터마이즈 하고자 하는 경우에는 특성을 주어야 할 때가 종종 있다.

typename

  1. 템플릿 매개변수(template-parameter)에 의존하는 한정된 이름(qualified-name)은 암묵적으로 하나의 형식 이름으로 간주한다.
  2. 기반 클래스 지정자(base-specifier)나 멤버 초기화식(mem-initializer) 에서는 사용할 수 없다.
    템플릿 타입 매개변수를 선언할 때는 class와 typename의 뜻 차이가 없다. c++의 관점에서 보면 템플릿 매개변수를 선언하는 경우의 class 와 typename은 완전히 같은 의미이다.

typename 키워드의 기능

ex) 잘못된 코드

template <typename T>
    class MyTypeClass
    {
      public:
      typedef T A;
      static int B;
      class C{};
      static void D( void ){}
    };

    void foo()
    {
      ...
      MyTypeClass<int>::A *E;  //1번 = 하위 타입인 A의 포인터 변수 E를 선언
      MyTypeClass<int>::B *F;  //2번 = 정적 변수 B와 변수 F를 곱셈하는 코드
      MyTypeClass<int>::C *G;  //3번 = 하위 클래스 C의 포인트 변수 G를 선언
      MyTypeClass<int>::D *H;  //4번 = 정적 함수 D와 변수 H를 곱셈하는 코드
    }

코드 타입이 똑같다. 그렇기 때문에 c++에서는 'A는 타입이야' 라고 알려주기 위해 typename을 사용한다.

void foo()
    {
      ...
      typename MyTypeClass<int>::A *C;  //1번
      MyTypeClass<int>::B *D;  //2번
    }

출처

링크텍스트

좋은 웹페이지 즐겨찾기