Programming/Programming2018. 1. 11. 04:00

1.   복합 타입


복합 타입(Compound Type)은 다른 타입을 사용해 정의한 타입. C++에서는 대표적으로 참조자와 포인터가 있다.


-       참조자

참조자(Reference)는 객체에 별칭을 정의함.

참조자로 참조하는다른 타입이 곧 참조자의 타입.

참조자 타입을 정의할 때는 선언자를 &d 형식으로 쓰는데, 여기서 d는 선언할 이름.


int num = 10;

int &refNum = num;

refNum += 2; // num 2를 더하는 것과 같다.

int &refNum2; // 오류. 참조자는 초기화해야 한다.

int ii = refNum; // ii = num과 같다.


변수를 초기화할 때는 초기 값을 생성하는 객체에 복사해 넣지만, 참조자를 정의할 때는 초기 값을 복사하는 것이 아닌 참조자를 초기화식에 결합함. 일단 초기화 한 후에는 참조자는 자신의 초기 객체와 결합한 채로 남기 때문에 반드시 초기화 해야 함.

참조자는 별칭. 객체가 아니며, 이미 존재하고 있는 객체에 대한 다른 이름이라고 보아야 함.

 

-       포인터

포인터는 다른 타입을 가리키는 복합 타입.

참조자처럼 다른 타입에 직접적으로 접근하는데 사용됨. 하지만 참조자와는 다르게 포인터는 그 자체로 객체임. , 초기화 하지 않고 정의 가능.

포인터는 대입하거나 복사할 수 있으며, 포인터 하나가 생명 주기 동안 여러 다른 객체를 가리킬 수 있음.


void* 포인터

void* 타입은 모든 객체의 주소를 담을 수 있는 특별한 포인터 타입. 가리키는 객체의 타입은 알 수 없음.

할 수 있는 일이 제한적. 가리키는 객체에 연산을 할 수 없음.

일반적으로 메모리를 메모리로 다루기 위해서 사용함.

 

참조자는 객체가 아니기 때문에 참조자에 대한 포인터는 존재하지 않지만, 포인터는 그 자체로 객체이기 때문에 포인터에 대한 참조자는 존재할 수 있음.

 



2.   Const 한정자


변수의 값을 바꿀 수 없도록 정의하고 싶을 때 사용.


상위와 하위

포인터 그 자체가 const일 경우 top-level(상위) const, 가리키는 대상 객체가 const일 경우는 low-level(하위) const라고 함.


int i=10;

const int ci = 100;

int *const p1 = &i; // 상위 const

const int *p2 = &ci; // 하위 const

 

객체를 복사할 때 상위 const는 무시하지만, 하위 const는 절대 무시하지 않음. 객체를 복사할 때, 두 객체 모두에 하위 const 한정 표시가 있거나 두 객체 타입을 서로 변환할 수 있어야 함.

일반적으로 const가 아닌 객체는 const 객체로 변환할 수 있지만, 그 반대는 아님.

 

constexpr과 상수 표현식

상수 표현식(constant expression)은 컴파일 중에 값을 평가할 수 있으며, 그 값을 바꿀 수 없는 표현식.

객체나 표현식이 상수 표현식인지 여부는 타입과 초기 값에 따름.


const int a = 20; // O

const int b = a+1; // O

int c = 27; // X, 값이 바뀔 수 있음

const int d = getScale(); // X, 초기 값을 알 수 없음

 

constexpr 변수

변수가 상수 표현식인지 컴파일러에서 확인하게 할 수 있음.

constexpr로 선언한 변수는 암시적으로 const이므로 상수 표현식으로 초기화해야 함.


constexpr int a = 20; // O

constexpr int b = a+1; // O

constexpr int c = getScale(); // getScale constexpr 함수 일 때만 가능

 

상수 표현식은 컴파일 중에 평가할 수 있으므로 constexpr 선언에 쓸 수 있는 타입은 제한적.

constexpr을 사용할 수 있는 타입을 상수타입(literal type)이라고 함.

 

constexpr 선언에서 포인터를 정의하면 constexpr는 포인터가 가리키는 타입이 아닌 포인터 자체에 적용됨.


const int* p = i;

constexpr int* q = i;

 

p const int형에 대한 포인터, q int형에 대한 const 포인터가 됨.

 



3.   그 외


-       타입 별칭(Type alias)

typedef 혹은 using을 사용해 복잡한 타입 정의를 간단하게 할 수 있음.


typedef unsigned int UINT;

using UINT = unsigned int;


using을 사용해 타입 별칭을 정의하는 것을 별칭 선언(alias declaration)이라 함.

 

-       Auto 타입 지정자

auto 타입 지정자는 int, double과 같은 특정 타입을 명명하는 타입 지정자와 달리 컴파일러에서 초기 값을 통해 타입을 추론하도록 함. 그러므로, auto를 타입 지정자로 사용하는 변수에는 반드시 초기 값이 있어야 함.

auto는 일반적으로 상위 const를 무시하므로, 추론한 타입에 상위 const가 있으려면 명시적으로 지정해야 함.


int i=0;

const int ci = i;

auto a = &ci; // aconst int*.

const auto b = &ci; // bconst int* const

 


-       decltype 타입 지정자

변수를 초기화 하는 데 표현식을 사용하는 것이 아니라 컴파일러에서 표현식으로부터 추론한 타입으로 변수를 정의하고 싶을 때 사용.

컴파일러에서는 타입을 결정하기 위해 표현식을 분석할 뿐, 평가하지는 않음.

decltype(func()) sum = a; // sum의 타입은 func가 반환하는 타입

decltype을 적용하는 타입이 변수이면 상위 const와 참조자를 포함해 대상 변수의 타입을 반환함.

적용하는 타입이 변수가 아닌 표현식이면 해당 표현식에서 반환하는 타입을 얻음.


int r=0, *pr=&r, &i = r;

decltype(r) a=0;

decltype(r+1) c = 1;

decltype(i) d = c;

decltype(*pr) b = a;


dint& 타입, b 또한 int& 타입이므로 초기화는 필수적임.

 

 

Posted by BinZIP