프로그래밍/C,C++

C++ 연산자 오버로딩

MAKGA 2018. 4. 25. 19:21
320x100

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);

}

};

320x100

'프로그래밍 > 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