
우리는 이제까지 다양한 연산자를 사용했습니다
+,-,*,/,% ...
그리고 기본 자료형의 변수를 만들고 그들을 연산해주었습니다
그런데 클래스나 구조체 자료형도 그대로 연산이 될까요?
스스로 설계한 자료형은 연산자도 스스로 만들어줘야합니다
Class TestClass
{
private:
int m_i;
public:
TestClass(){}
~TestClass(){}
}
int main()
{
int a = 100, int b = 200;
int c = a + b; // 300
TestClass ta;
TestClass tb;
TestClass tc = ta + tb; // 오류 발생
}
전역함수와 멤버변수 두 가지 버전으로 한 번 만들어봅시다
Class TestClass
{
private:
int m_i;
public:
TestClass(){}
~TestClass(){}
// 전역 함수는 클래스 멤버 변수에 접근을 못하므로 get,set함수가 필요
}
// 전역함수로 추가하기
TessClass operator+(TestClass _right, TestClass _left)
{
}
int main()
{
int a = 100, int b = 200;
int c = a + b; // 300
TestClass ta;
TestClass tb;
TestClass tc = ta + tb; // operator+(ta,tb)를 이렇게 표현 가능
}
Class TestClass
{
private:
int m_i;
public:
TestClass(){}
~TestClass(){}
int SetData(int _i)
{
m_Data = _i;
}
// 멤버함수로 추가하기
// 인자를 하나만 받음
// 호출자가 this
TestClass operator+(TestClass _other)
{
TestClass data;
data.m_Data = this->m_Data + _other->m_Data;
return data;
}
}
int main()
{
int a = 100, int b = 200;
int c = a + b; // 300
TestClass ta;
ta.SetData(10);
TestClass tb;
tb.SetData(100);
TestClass tc = ta + tb; // ta.operator+(tb)를 이렇게 표현 가능
}
그런데 갑분 생각해보아야 할 점
함수 내부의 지역변수가 return 될 때 왜 사라지지 않고, 호출했을 때 값을 받아올 수 있는 걸까요?
예를 들어봅시다.
int getInt()
{
int a = 1;
return a;
}
int main()
{
getInt();
}
int a는 지역변수고, 함수가 종료되면 사라질텐데 어떻게 return 할 수 있는 걸까요?
(사실 저도 안궁금해했음 당연한 거라고 생각함)
정답은 a 내부의 값을 레지스터 메모리에 저장시켜놓습니다.
위의 TestClass타입을 반환하는 data도 이런 식으로 리턴되어 값이 사라지지 않고 복사된 값을 받을 수 있게됩니다.
그리고 오퍼레이터는 내가 만든 기호 내부 식으로 연산을 하는 것이기 때문에 정의되어있는 연산자와 의미가 다를 수도 있습니다.
우리가 c++에서 아주 많이 사용하는 cout 객체도 그렇습니다.
cout.ostream::operator<<(10);
<<는 원래 비트 연산자지만,
입벌리고 있으니 먼가 출력해줄 거 같은 느낌적인 느낌이 드는 겁니다.
그러니 이런 식으로 만들고 사용하게 되었습니다.
// 멤버함수
void operator <<(int a)
{
printf("%d",a);
}
TestClass ta;
ta.operator<<(10) << 20; // 컴파일 에러
왜 문제가 될까요?
멤버 함수는 호출 객체가 필요합니다.
ta.operator<<(10)는 this 포인터로 operator 멤버 함수를 호출하여 10을 출력했는데, 그리곤 ta 객체로 돌아오지 못했기 때문입니다!
(대충 this 포인터가 아니라는 뜻)
그럼 다시 리턴 값으로 ta가 돌아오게 만들어봅시다.
TestClass* operator <<(int a)
{
printf("%d",a);
return this; // 자기 자신의 주소를 반환
}
*(*(*(ta << 40))<< 50)<< 60; //...
복사본이 아닌 원본을 참조하기 위해 리턴 받은 this를 참조하고 또 그 리턴 값을 참조 참조... 했는데 너무 불편하지 않을까요?
그래서 이렇게 바꿔보겠습니다.
TestClass& operator <<(int a)
// 레퍼런스는 원본을 받아도 주소가 넘어감
{
printf("%d",a);
return *this; // this는 이미 포인터 타입이므로 *를 붙여줘야 원본 참조
}
ta << 10 << 20 << 30;
이렇게 되면 우리가 이제껏 생각한대로 출력할 수 있게 됩니다.
...
정리할 내용 조금 더 있슴 -> 함수 주소값으로 endl 구현하는 거는 좀 나중에 하겠소