https://msdn.microsoft.com/ko-kr/library/5tk49fh2.aspx
연산자가 특정 클래스에 적용될 때, 그 동작 방식을 목적에 맞게 정의할 수 있는 기능.
모든 연산자가 오버로딩이 가능하지 않고, 새로운 연산자를 추가할 수 없다.
반드시 메서드로 오버로딩 해야 하는 연산자
어떤 연산자들은 클래스를 떠나서는 의미가 없으므로 반드시 클래스의 메서드로만 오버로딩 되어야 한다.
ex) operator=는 특정 클래스의 대입에 대해서만 의미가 있다.
반드시 전역 함수로 오버로딩해야 하는 연산자
연산자의 좌항에 목적하는 클래스 외에 다른 타입이 올 수 있어야만 한다면 전역 함수로서 오버로딩 해야 한다.
ex) operator<<나 operator>>
어느 것이나 상관없는 연산자는 virtual로 선언이 가능하도록 메서드로 구현을 권장한다.
class Coordinates
{
public:
Coordinates(int _x, int _y)
{
x = _x;
y = _y;
}
// 메소드
Coordinates operator+ (Coordinates& c) {
return Coordinates(x + c.x, y + c.y);
}
// 멤버함수 접근을 위한 friend 선언
friend Coordinates operator+(int num, Coordinates c);
private:
int x;
int y;
};
// 전역함수
Coordinates operator+(int num, Coordinates c)
{
c.x += num;
c.y+= num;
return c;
}
int main()
{
Coordinates c1(1, 2);
Coordinates c2(3, 4);
Coordinates c3 = c1 + c2; // 메소드
Coordinates c4 = 10 + c1; // 전역함수
system("pause");
}
전위연산자, 후위 연산자
class Coordinates
{
public:
Coordinates(int _x, int _y)
{
x = _x;
y = _y;
}
Coordinates& operator++(); // 사전 연산자
Coordinates operator++(int); // 사후 연산자
Coordinates& operator--(); // 사전 연산자
Coordinates operator--(int); // 사후 연산자
private:
int x;
int y;
};
Coordinates& Coordinates::operator++()
{
x = x + 1;
y = y + 1;
return *this;
}
Coordinates Coordinates::operator++(int)
{
Coordinates old(*this);
x = x + 1;
y = y + 1;
return old;
}
Coordinates& Coordinates::operator--()
{
x = x - 1;
y = y - 1;
return *this;
}
Coordinates Coordinates::operator--(int)
{
Coordinates old(*this);
x = x - 1;
y = y - 1;
return old;
}
int main()
{
Coordinates c1(1, 2);
Coordinates c2(3, 4);
++c1;
c2++;
return 0;
}
입출력 연산자의 오버로딩
class Coordinates
{
public:
Coordinates(int _x, int _y)
{
x = _x;
y = _y;
}
void set(int num)
{
x = num;
y = num;
}
friend std::ostream& operator<< (std::ostream ostr, const Coordinates& c);
friend std::istream& operator>>(std::istream istr, Coordinates& c);
private:
int x;
int y;
};
std::ostream& operator<< (std::ostream ostr, const Coordinates& c)
{
ostr << c.x << '\t' << c.y;
return ostr;
}
std::istream& operator>>(std::istream istr, Coordinates& c)
{
int temp;
istr >> temp;
c.x = temp;
c.y = temp;
return istr;
}
인덱싱 연산자 오버로딩
int& Array::operator[](size_t x)
{
if (x < 0)
throw std::out_of_range("");
if (x >= mSize)
resize(x + kAllocSize);
return mElems[x];
}
// 읽기 전용 operator[]
const int& Array::operator[](size_t x) const
{
if (x < 0 || x >= mSize) {
throw std::out_of_range("");
}
return mElems[x];
}
함수 호출 연산자 오버로딩
함수 호출 연산자를 가진 객체를 functor라고 하는데, 이렇게 만드는 이유는 함수 객체를 함수 포인터로 가장하여 콜백 함수로서 대신 넘겨질 수 있다.
class FunctionObject
{
public:
int operator() (int inParam); // 함수 호출 연산자
int doSquare(int inParam); // 일반 메서드
};
int FunctionObject::operator() (int inParam)
{
return doSquare(inParam);
}
int FunctionObject::doSquare(int inParam)
{
return inParam * inParam;
}
int main()
{
int x = 3, xSquard, xSquaredAgain;
FunctionObject square;
xSquard = square(x); // 함수 연산자의 호출
}
역참조 연산자의 오버로딩(*, ->, ->*)
클래스에서 역참조 연산자를 오버로딩하면 해당 클래스 객체를 포인터처럼 이용할 수 있다.(스마트포인터)
operator*의 구현
template <typename T>
class Pointer
{
public:
Pointer(T* inPtr);
virtual Pointer();
T& operator();
const T& operator*() const;
private:
T & mPtr;
};
template<typename T>
T& Pointer<T>::operator*()
{
return *mPtr;
}
operator->의 구현
template <typename T>
class Pointer
{
public:
Pointer(T* inPtr);
virtual Pointer();
T* operator->();
const T* operator()->() const;
private:
T & mPtr;
};
template<typename T>
T* Pointer<T>::operator->()
{
return mPtr;
}
변환연산자
변환 연산자는 리턴 타입이 없고, 수정 사항이 없기 때문에 const로 선언된다.
class SpreadsheetCell
{
public:
SpreadsheetCell(double _d)
{
mValue = _d;
mString = _d;
}
explicit operator double() const // 변환연산자에 explicit은 C++11 이후 가능
{
return mValue;
}
operator std::string() const
{
return mString;
}
private:
double mValue;
std::string mString;
};
int main()
{
// double에서 SpreadsheetCell로 암묵적인 변환. double 타입 생성자 호출
SpreadsheetCell cell = 6.6;
// 문자열 변환 연산자
std::string str = cell;
// double 변환 연산자
double d1 = static_cast<double>(cell);
}
논리 표현식으로의 변환
template<typename T>
class Pointer
{
public:
operator void*() const
{
return mPtr;
}
private:
T * mPtr;
};
void process(Pointer<SpreadsheetCell>& p)
{
if (p != nullptr) { std::cout << "not nullptr" << std::endl; }
}
int main()
{
Pointer<SpreadsheetCell> smartCell(nullptr);
// void*
process(smartCell);
}
메모리 할당/해제 연산자의 오버로딩
메모리 할당/해제의 커스터마아징은 특정 클래스 단위로 할 수도 있고, 프로그램 전체적으로 할 수도 있다.
작은 크기의 객체를 자주 생성/소멸할 때 발생할 수 있는 메모리 파편화 문제를 해결할 수 있다.
class Memory
{
public:
Memory();
virtual ~Memory();
void* operator new(std::size_t size) {
return ::operator new(size);
}
void* operator new[](std::size_t size) {
return operator new[](size);
}
void* operator new(std::size_t size, const std::nothrow_t&) noexcept {
return ::operator new(size, nothrow);
}
void* operator new[](std::size_t size, const std::nothrow_t&) noexcept {
return ::operator new[](size, nothrow);
}
void* operator new(std::size_t size, int parm) {
Log(parm); // 이런식으로 활용 가능
return ::operator new(size);
}
void operator delete(void* ptr) noexcept {
::operator delete(ptr);
}
void operator delete[](void* ptr) noexcept {
::operator delete[](ptr);
}
void operator delete(void* ptr, const std::nothrow_t&) noexcept {
::operator delete(ptr, nothrow);
}
void operator delete[](void* ptr, const std::nothrow_t&) noexcept {
::operator delete[](ptr, nothrow);
}
};
'프로그래밍 > C,C++' 카테고리의 다른 글
비동기 함수 정리 (0) | 2021.03.22 |
---|---|
가상 메모리 및 Large Address Aware (0) | 2020.02.19 |
STL 커스터마이징 (0) | 2018.04.18 |
유틸리티 라이브러리 (0) | 2018.04.18 |
문자열과 정규 표현식 (0) | 2018.04.15 |