C++ Various overloading part 2.
1.C++ style casting
C에서는, 캐스팅은 크게 2 가지 방법으로 발생한다. 하나는 그냥 컴파일러에서 알아서 캐스팅 하는 암시적(implicit) 캐스팅과, 직접 ~!@#$하게 캐스팅 하라고 지정하는 명시적(explicit) 캐스팅이 있다. 암시적 캐스팅의 경우 int 와 double 변수와의 덧셈을 수행할 때, int 형 변수가 자동으로 double 변수로 캐스팅 되는 것과 같은 것을 말하고, 명시적 캐스팅의 경우 예를 들어 void * 타입의 주소를 특정 구조체 포인터 타입의 주소로 바꾼다던지 등의 캐스팅이 있다.
명시적 캐스팅은 아래와 같다.
ptr = (Something *)other_ptr;
int_variable = (int) float_variable;
function((int)variable);
함수 호출에도 괄호를 사용하는데, 괄호가 너무 많아지게 된다면, 여러모로 불편하다. 하지만, 문제는 그 뿐만이 아니고,사실 캐스팅을 하는데에는 여러가지 이유가 있기 마련인데, 위와 같은 C형식 캐스팅에서는 읽는이가 그 캐스팅의 의미를 명확하게 알 수 없다. 하지만 C++ 에서는 다음과 같은 4 가지의 캐스팅을 제공하고 있다.
1.static_cast : 흔히 생각하는, 언어적 차원에서 지원하는 일반적인 타입 변환.
2.const_cast : 객체의 상수성(const) 를 없애는 타입 변환. 쉽게 말해 const int 가 int 로 바뀐다.
3.dynamic_cast : 파생 클래스 사이에서의 다운 캐스팅.
4.reinterpret_cast : 위험을 감수하고 하는 캐스팅으로 서로 관련이 없는 포인터들 사이의 캐스팅.
이 때 이러한 캐스팅을 사용하는 방법은 다음과 같다.
[원하는 캐스팅 종류][바꾸려는 타입][무엇을 바꿀 것인가?]
static_cast(float_variable) ; //C++ ========================= (int)(float_variable) //C
arr[1][2][3][4]========Q
(T)[2][3][4]=========W
(T')[3][4]=========E
T'''========R
그렇다면, 여러개의 [] 들을 어떻게 처리하냐면 예를 들어 Q를 하였을 때, 제일 먼저 arr[1] 이 처리되며, 첫 번째 차원으로 1 을 선택했다는 정보가 담긴 어떠한 객체 T 를 리턴한다.
그리고 W가 수행이 된다. 이 T 또한 operator[] 가 있어서, 두번째 차원으로 2 를 선택했다는 정보가 담긴 객체 T' 을 리턴한다.
그렇다면 이제E가 되겠고, 마찬가지로 계속 진행하게 된다면 R이 남게 된다.
즉 이 T''' 가 int 타입임을 바라고 있다.
그런데 도대체 이를 어떻게 구현해야 할까?
일단 Array 가 아닌 새로운 타입의 객체를 만들어야 한다는 것만은 분명한다.
arr[1] = 3;================Q
arr[1] = 3;===============W
arr[1][2] = 3;===========R
1 차원 Array 배열에 대해서 Q과 같은 문장은 말이 안되기 때문이다.
그렇다고 해서 operator[] 가 int& 타입을 리턴할 수 도 없다.
왜냐하면 만일 int& 타입을 리턴하였을 경우에 1 차원 배열인 W과 같은 문장은 쉽게 처리할 수 있다고 하지만, 그보다 고차원 배열에 대해서 어떻게 할 것인가?
arr[1] 의 리턴 타입이 int& 라면 int 에 대한 operator[] 는 정의되어 있지도 않고 정의 할 수 도 없다. '그렇다면 상황에 따라서 1 차원이면 int 를, 그 보다 고차원 배열이면 다른 것을 리턴하면 되지 않냐?' 라고 물을 수 있지만 '오버로딩' 의 원칙 상 동일한 인자를 받는 함수에 대해서는 한 가지 리턴 타입만이 가능하다. 하지만 조금만 기억을 더듬어 올라간다면, 필요할 때 int 처럼 작동하지만 int 가 아닌 클래스를 만들 수 있었다. 바로 int 의 Wrapper 클래스.. int 의 Wrapper 클래스는 타입 변환 연산자를 제공해서 int 와의 연산을 수행하거나, 대입등을 할 때 마치 int 처럼 작동하도록 만들 수 있다.
그렇다면 우리는 operator[] 가 int 의 Wrapper 클래스 객체를 리턴해서, 실제 int 값에 접근할 때에는 int 변수 처럼 행동하고, 위에서 T 나 T' 처럼 원소에 접근해 가는 중간 단계의 산물일 경우, 그 중간 단계의 정보를 포함하는 것으로 사용하면 된다.
class Int
{
void* data;
int level;
Array* array;
};
먼저 level 정보는 반드시 포함하고 있어야만 한다. 왜냐하면 이 Int 가 맨 마지막 '실제 int 정보' 를 포함하고 있는 객체인지, 아니면 원소를 참조해 나가는 중간 과정에서의 산물인지를 구별할 수 있어야 하기 때문이다.
arr[1][2];를 생각해 볼 때 맨 처음 arr[1] 은 level 이 1 인 Int 가 리턴된다. 이 때, 이는 int 데이터가 아니라, [1][2] 를 참조해 나가기 위한 중간 과정이다. (이 것을 Int 가 어떻게 구별하냐면, Int 가 가지고 있는 array 의 dim 정보를 참조하면 된다)
이 때의 Int 에는 '현재 arr[1] 를 가리키고 있음' 에 대한 정보가 Int 의 data 에 들어가 있다. 그 다음에 Int 의 operator[] 를 수행하게 된다면 (따라서 Int 클래스의 operator[] 역시 만들어야 한다), 이번에는 level 이 2 인 Int 가 리턴이 된다.
사용자가 level 이 2 인 Int 에 대입 연산을 하게 된다면, void * data 를 int 원소를 가리키고 있는 주소로 해석해서 실제로 int 변수 처럼 대입이 수행이 될 것이다.
참고로 array 는 어떤 배열의 Int 인지 가리키는 역할을 한다.'#Programming Language > C++' 카테고리의 다른 글
C++ Virtual function. (0) | 2018.04.01 |
---|---|
C++ Standard String & Inheritance. (0) | 2018.04.01 |
C++ Various overloading. (0) | 2018.04.01 |
C++ Operator overloading. (0) | 2018.04.01 |
C++ Your Own String Class (0) | 2018.04.01 |