함수가 오버로딩이 되어 다양한 기능을 제공하는 것처럼 연산자 또한 오버로딩이 가능하다.
FirstOperationOverloading.cpp
#include <iostream>
using namespace std;
class Point
{
private:
int xpos, ypos;
public:
Point(int x = 0, int y = 0) : xpos(x), ypos(y)
{
}
void ShowPosition() const
{
cout << '[' << xpos << ", " << ypos << ']' << endl;
}
Point operator+(const Point& ref)
{
Point pos(xpos + ref.xpos, ypos + ref.ypos);
return pos;
}
};
int main(void)
{
Point pos1(3, 4);
Point pos2(10, 20);
Point pos3 = pos1.operator+(pos2); // Point pos3 = pos1+pos2;
pos1.ShowPosition();
pos2.ShowPosition();
pos3.ShowPosition();
return 0;
}
위의 main함수 내에서 pos3을 pos1.operator+(pos2)라고 정의하였지만 pos1+pos2로 대입을 하여도 컴파일이 가능함. 즉 '+' 자체가 .operator+로 해석이되어 컴파일러가 처리해준다는 것을 알 수 있음.
멤버함수에 의한 연산자 오버로딩
전역함수에 의한 연산자 오버로딩
pos1.operator+(pos2); // 멤버함수 오버로딩
operator_(pos1, pos2); // 전역함수 오버로딩
두 가지 동시에 오버로딩이 된 경우 멤버함수 먼저 우선시되어 호출
전역함수 기반 오버로딩 예시
GFunctionOverloading
#include <iostream>
using namespace std;
class Point
{
private:
int xpos, ypos;
public:
Point(int x = 0, int y = 0) : xpos(x), ypos(y)
{
}
void ShowPosition() const
{
cout << '[' << xpos << ", " << ypos << ']' << endl;
}
friend Point operator+(const Point& pos1, const Point& pos2);
};
Point operator+(const Point& pos1, const Point& pos2)
{
Point pos(pos1.xpos + pos2.xpos, pos1.ypos + pos2.ypos);
return pos;
}
int main(void)
{
Point pos1(3, 4);
Point pos2(10, 20);
Point pos3 = pos1 + pos2;
pos1.ShowPosition();
pos2.ShowPosition();
pos3.ShowPosition();
return 0;
}
위 예제의 friend선언을 보고 operator+ 함수가 Point 클래스의 private 영역에 접근이 가능함 뿐만이 아니라 이 클래스가 +연산에 대해서 연산자 오버로딩이 되어 있음을 확인할 수 있어야 함!
C++에서 전위 및 후위 연산에 대한 해석 방식
++pos -> pos.operator++();
pos++ -> pos.operator++(int);
--pos -> pos.operator--();
pos-- -> pos.opreator--(int);
관련예제
PostOpndOveraloding.cpp
#include <iostream>
using namespace std;
class Point
{
private:
int xpos, ypos;
public:
Point(int x= 0, int y = 0): xpos(x), ypos(y)
{}
void ShowPosition() const
{
cout << "[" << xpos << ", " << ypos << "]" << endl;
}
Point& operator++() // 전위 증가
{
xpos += 1;
ypos += 1;
return *this;
}
const Point operator++(int) // 후위 증가
{
const Point retobj(xpos, ypos); // const Point retobj(*this);
xpos += 1;
ypos += 1;
return retobj;
}
friend Point& operator--(Point& ref);
friend const Point operator--(Point& ref, int);
};
Point& operator--(Point& ref) // 전위 감소
{
ref.xpos -= 1;
ref.ypos -= 1;
return ref;
}
const Point operator--(Point& ref, int) // 후위감소
{
const Point retobj(ref); // const 객체라고함
ref.xpos -= 1;
ref.ypos -= 1;
return retobj;
}
int main(void)
{
Point pos(3, 5);
Point cpy;
cpy = pos--;
cpy.ShowPosition();
pos.ShowPosition();
cpy = pos++;
cpy.ShowPosition();
pos.ShowPosition();
return 0;
}
후위 증가의 효과를 정의하기위해 operator++(int) 와 operator--(int)내의 함수에서 const를 사용하여 함수 내에서 retobj의 변경을 막겠다는 의도와 const형 임시객체를 반환하고 그 뒤에 값이 변경되는 후위증가 및 감소의 특성을 반영하였다.
위 예제와 관련한 전위 증감과 후위 증감에 대한 것
일반적으로 C++의 연산 특성은 다음과 같다.
int main(void)
{
int num = 100;
(num++)++; // 컴파일에러
(num--)--; // 컴파일 에러
++(++num); // 컴파일 성공
--(--num); // 컴파일 성공
}
위 PostOpndOveraloding.cpp
예제에서 후위 증감함수들을 const를 사용하여 표현한 이유는 위의 특성을 반영하여 후위증감 시 const객체를 반환하지만 함수들은 증가의 경우 함수가 const함수가 아니고 감소의 경우 매개변수 참조자가 const로 선언되지 않았기 때문에 에러를 발생시킨다.
일반적으로 연산자 오버로딩에서 pos라는 객체가 존재한다고 할시
pos x 3은 되지만 (pos.operator*(3))
3 x pos와 같이 연산을 하려면 전역함수의 형태로 곱셈 연산자를 오버로딩 하는 수 밖에 없다.
관련예제
CommuMultipleOperation.cpp
#include <iostream>
using namespace std;
class Point
{
private:
int xpos, ypos;
public:
Point(int x = 0, int y = 0) : xpos(x), ypos(y)
{
}
void ShowPosition() const
{
cout << "[" << xpos << ", " << ypos << "]" << endl;
}
Point operator*(int times)
{
Point pos(xpos * times, ypos * times);
return pos;
}
friend Point operator*(int times, Point& ref);
};
Point operator*(int times, Point& ref)
{
return ref * times;
}
int main(void)
{
Point pos(1, 2);
Point cpy;
cpy = 3 * pos;
cpy.ShowPosition();
cpy = 2 * pos * 3;
cpy.ShowPosition();
return 0;
}
전역함수에 Pointer operator*(int times, Point& ref)로 정의를 해주어 곱셈 연산자의 교환법칙이 성립하도록 하였다.
ConsoleOutput.cpp
#include <iostream>
namespace mystd
{
using namespace std;
class ostream
{
public:
void operator<< (const char* str)
{
printf("%s", str);
}
void operator<< (char* str)
{
printf("%c", str);
}
void operator<< (int num)
{
printf("%d", num);
}
void operator<< (double e)
{
printf("%g", e);
}
void operator<< (ostream& (*fp)(ostream& ostm))
{
fp(*this);
}
};
ostream& endl(ostream& ostm)
{
ostm << '\n';
fflush(stdout);
return ostm;
}
ostream cout;
}
int main(void)
{
using mystd::cout;
using mystd::endl;
cout << "Simple String";
cout << endl;
cout << 3.14;
cout << endl;
cout << 123;
endl(cout);
}
예제를 실행하면 이상하게 '\n'이 원래는 공백으로 표시되어 결과가 나와야하는데 아스키 코드 값인 10이 출력이 된다... 왜 이런 현상이 발생하는 지는 모르겠다.. ---> main함수에서 using std::cout, std::endl을 사용하여 컴파일을 하면 정상적으로 작동이 된다.
<<, >> 를 오버로딩하려면 ostream 클래스 멤버함수에 정정하거나 전역함수에 의한 방법 둘 중하나를 해야하는데 전자는 불가능하므로 전역함수를 사용하는 방법을 선택!
PointConsoleOutput.cpp
#include <iostream>
using namespace std;
class Point
{
private:
int xpos, ypos;
public:
Point(int x = 0, int y = 0) : xpos(x), ypos(y)
{
}
void ShowPosition() const
{
cout << '[' << xpos << ", " << ypos << ']' << endl;
}
friend ostream& operator<< (ostream&, const Point&);
};
ostream& operator<<(ostream& os, const Point& pos)
{
os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl;
return os;
}
int main(void)
{
Point pos1(1, 3);
cout << pos1;
Point pos2(101, 303);
cout << pos2;
return 0;
}
cout가 ostream의 클래스 객체이고 인자로 ostream형 객체와 Point 참조형을 받아 다음과 같이 함수를 구성하면 된다.