연산자 오버로딩은 C++이 제시하는 하나의 약속이다


operator 키워드와 연산자를 묶어서 함수의 이름을 정의하면, 함수의 이름을통한 호출뿐만아니라 연산자를 이용한 함수의 호출을 허용해준다. 

연산자 오버로딩또한 const 선언이 가능하다.


연산자를 오버로딩하는 두가지 방법


멤버함수에 의한 연산자 오버로딩 ( 함수의 호출 : pos1+pos2; = pos1.operator+(pos2); )

전역함수에 의한 연산자 오버로딩 ( 함수의 호출 : pos1+pos2; = operator+(pos1,pos2); )


동일한 자료형을 대상으로 전역함수 , 멤버함수기반으로 동시에 오버로딩할경우 , 멤버함수 기반으로 선언된 함수가 우선시되어 호출된다.

전역함수로 연산자를 오버로딩할때 , 클래스의 private 멤버에 접근하고싶다면 , friend 선언을 통해 하는것이 적절하다. 

또한 friend 선언을 통해 클래스에 연산자오버로딩이 되어있는 사실을 쉽게 확인할 수 있다.


멤버함수 기반으로만 오버로딩이 가능한 연산자


이는 객체를 대상으로해야만 의미가 통하는 연산자들이기때문에 , 멤버함수기반으로만 연산자의 오버로딩을 허용한다.

= , () , [] , ->


연산자 오버로딩의 주의사항


1. 본래의 의도를 벗어난 연산자 오버로딩은 좋지않다.

2. 연산자의 우선순위와 결합성은 바뀌지 않는다.

3. 매개변수의 디폴트값 설정이 불가능하다.

4. 연산자의 순수기능을 빼앗을 수 없다.


단항 연산자의 오버로딩


증가 , 감소연산자 ( ++ , -- )


멤버함수에 의한 연산자 오버로딩 ( 함수의 호출 : ++pos; = pos.operator++(); )

전역함수에 의한 연산자 오버로딩 ( 함수의 호출 : ++pos; = pos.operator++(pos); )


전위증가 후위증가의 구분


C++ 에서는 전위및 후위 연산에 대한 해석방식에대해 규칙을 정해놓고있다.

키워드 int 를 이용해서 후위연산에대한 함수와 전위연산에 대한 함수를 구분한다 . int 는 구분의 목적으로 선택된것일뿐 아무상관이없다 .

중요한것은 후위연산과 전위연산의 차이를 보이도록 오버로딩하는것이다.


++pos = pos.operator();

pos++ = pos.operator(int);


Point& operator++() //전위증가

{

xpos += 1;

ypos += 1;

return *this; // 자기자신 객체 반환

}

const Point operator++(int) // 후위증가, const 객체로 반환 -> 객체를 상수화 ( 이중 후위연산을 막아서 C++의 연산특성을 그대로 반영하기위함 )

{

const Point retobj(xpos,ypos) // 생성자 , const Point retobj(*this)로 변환가능

xpos +=1;

ypos +=1;

return retobj;

}


const 선언과 const 객체


객체에 const 선언을한다는것은 , 객체를 상수화해서 객체에 저장된값의 변경을 허용하지않겠다는 뜻이다. 그래서 const 객체를 대상으로는 const 로 선언된 함수만 호출이 가능하다. 이때 , const 객체를 대상으로 참조자를 선언할때는 참조자도 const 로 선언해야한다. ( const Point &ref = pos; )


교환법칙


기본적으로 연산에 사용되는 두 피연산자의 자료형은 일치해야하는데 , 연산자 오버로딩을 사용하면 이러한 연산규칙에 예외를 둘 수 있다.


Point operator*(int times)

{

Point pos (xpos*times , ypos* times);

return pos;

}


-- main --


Point pos(1,2);

Point cos = pos*3;



이때 , 반드시 Point객체가 *연산자의 왼편에 와야한다. ( cos = 3.pos; // 3.operator*(pos) 로는 해석 불가능)


교환법칙 성립을 위한 구현


이를 위해서는 전역함수의 형태로 곱셈연산자를 오버로딩하는수밖에없다 . 


Point operator* ( int times , Point &ref)

{

Point pos (ref.xpos*times , ref.ypos*times);

return pos;

}


혹은 3*pos 를 pos*3으로 바꾸는 형태로 오버로딩해도된다.


Point operator* (int times , Point &ref)

{

return ref*times;

}


cout , cin 그리고 endl 의 정체


#include <iostream>


namespace mystd

{

using namesapce std;


class ostream

{

public :

ostream& operator<< (char *str )

{

printf("%s",str);

return *this; // 연이은 <<연산을 위해 자기자신객체를 반환할 필요가 있다.

}

ostream& operator<< (char str)

{

printf("%c",str);

return *this;

}

ostream& operator<< (int num)

{

printf("%d",num);

return *this;

}

ostream& operator<< (double num)

{

printf("%g",num);

return *this;

}

ostream operator<< (ostream& (*fp) (ostream& ostm) ) // 함수포인터( 함수를 매개인자로 받을수있다 )

{

return fp(*this);

}

};

ostream& endl ( ostream& ostm)

{

ostm<<'\n';

fflush(stdout); // 출력버퍼 비움

return ostm;

}


ostream cout; // cout 은 ostream클래스의 객체이다


};


<< , >> 연산자의 오버로딩


cout<<pos<<endl;와 같은 연산이 가능하고자한다면 , << 연산자를 오버로딩해야한다.


cout은 ostream 클래스의 객체이다.

ostream은 namespace std 안에 선언되어있으며 , 이의 사용을 위해서는 헤더파일 iostream 을 포함해야한다.


멤버함수에 의한 방법을 선택하려면  cout 객체의 멤버함수를 하나 추가해야하므로 ostream 클래스를 정정해야하는데 , 이는 불가능한방법이니 전역함수에 의한 방법을 선택할 수 밖에없다.


class Point

{

...

friend ostream& operator<<(ostream& , const Point&);

{;


ostream& operator<<(ostream& os, const Point& pos)

{

os<<'['<<pos.xpos<<" , "<<pos.ypos<<']'<<endl;

return os; // 연속된 << 연산을 위함 ( cout<<pos<<"12"<<endl; )

}



+ Recent posts