[C++] 7. 연산자 오버로딩

2011. 6. 1. 22:32C++


1. 연산자 오버로딩 2가지 방법
 
 operator 키워드 + 연산자 를 붙여서 함수명을 만들경우 해당 연산자를 오버로딩 하게 된다.

 ex> Point p1,p2;
     Point p3 = p1+p2;  => p1.operator+(p2) 가 된다.
                        => operator+(p1,p2) 가 된다.

 class Point {
    // 멤버 함수에 의한 연산자 오버로딩
    void operator+(int value);
    Point operator+(const Point& p);

    // 전역함수 연산자 오버로딩 (friend 키워드 사용)
    // friend를 붙이면 해당 전역함수에서 이클래스의 private 변수/함수에 접근 가능하다.
    friend Point operator+(const Point&, const Point&)
 }

 Point operator+(const Point& p1, const Point& p2)
 {
    Point temp(p1.x+p2.x, p1.y+p2.y);
    return temp;
 }

2. 단항 연산자 오버로딩

 class Point {
 Point& operator++(); // 멤버함수, Point& 를 리턴해야 ++(++) 방식이 가능하다.
 friend Point& operator--(Point& p); // 전역함수
 }

 // 전역 함수
 Point& operator--(Point& p) {
 p.x--;
 p.y--;
 return p;
 }

 @ ++(++p) 와 --(--p)  는 어떤경우 인가.
 ++(++p) => operator++( operator++(p) ) 간된다. 즉 해당 operator 함수는
 Point& 레퍼런스를 리턴해야 이렇게 호출이 가능하다.

3. 단항연선자의 선연산과 후연산의 구분
 ++p : 즉시 증가한후 다음라인으로 넘어간다. p.operator++() : 멤버
 p++ : 다음라인에서 증가된다.  p.operator++(int); // int 매개변수가 아닌 구분을 위한 약속입니

다.

 class Point {
 Point& operator++(); // 선증가
 Point operator++(int); // 후증가
 }

 // 선증가
 Point& Point::operator++() {
 x++;
 y++;
 return *this; // 증가시킨후 현재 객체 레퍼런스를 리턴한다.
 }

 // 후증가형식으로 연산자 오버로딩 구현방법
 Point Point::operator++(int) {
 Point temp(x,y); // 증가전의 객체를 생성한다.
 x++;
 y++;

 /**
    로컬 객체이므로 참조값을 넘길수가 없습니다. 그래서 복사해서 넘겨야 합니다.
           따라서 Point& 가아닌 Point를 리턴합니다.
 */
 return temp; // 증가전의 데이터를 리턴한다.
 }


4. 연산자 교환 법칙 해결하기
 p + 10 == 10 + p

 class Point {
 Point operator+(int value);
 }

 int main(void) {
 Point p1;
  Point p2 = p1 + 3;  ==> p1.operator+(3); 을 호출하게 된다.
 Point p3 = 3+p1; ==> 불가능하다. 해결방법은? 전역으로 선언하면 된다.
 }

 교환법칙을 해결하려면 전역 으로 연산자를 오버로딩 하면 됩니다.
 해결 예>
  Point operator+(int value, Point& p) {
 return p+value; // 이런식으로 변환해준다.
  }

5. 임시 객체
 임시 객체란 이름이 없는 객체를 말합니다.
 int a = 3 + 4; // 메모리로 해석하면 3,4도 메모리에 올라갑니다. 따라서 12bytes가 할당됩니다.
 여기서 3,4가 바로 임시 객체 형태이며 다음라인으로 넘어가면 자동으로 메모리에서 해지 됩니다.

 - 컴파일러에 의해서 최적화 되어 빠르므로 특정 장소요 사용하면 좋습니다.
   객체에는 Point(3,4); 와 같이 사용합니다.즉 이름이 없습니다.

 Point Point::operator+(int value) {
        // 즉 단순 생성후 리턴형에 복사하기 위해서라면 임시 객체를 사용하는것이 좋다.
 return Point(x+value,y+value);
 }


6. count, cin 그리고 endl의 비밀
 - 

/*
   HelloWorldReview2.cpp
*/
#include<stdio.h>

namespace mystd  //mystd라는 이름공간 시작.
{  
 char* endl="\n";
 class ostream // 클래스 ostream 정의
 {
 public:
  ostream& operator<<(char * str) {
   printf("%s", str);
   return *this;
  }
  ostream& operator<<(int i) {
   printf("%d", i);
   return *this;
  } 
  ostream& operator<<(double i) {
   printf("%e", i);
   return *this;
  } 
 };

 ostream cout;  //ostream 객체 생성
} // mystd 이름공간 끝.

using mystd::cout;
using mystd::endl;

int main()
{
 cout<<"Hello World"<<endl<<3.14<<endl;
 return 0;
}


* 객체 정보를 출력하려면
  cout<<p -> cout.operator<<(p);  // x 불가능함. 멤버함수로는 불가능함.
                                  // 표준 라이브러리에 선언되어 있지 않기때문에 불가능 합니다.

  cout<<p -> operator<<(cout,p);  // o 전역함수로 가능함.
                                  // 직접 제작하는것이기 때문에 가능합니다.

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


 

 class Point {
 friend ostream& operator<<(ostream& os, const Point& p);
 }
 ostream& operator<<(ostream& os, const Point& p) {
 os<<"["<<p.x<<","<<p.y<<"]"<<endl; // Point 객체 정보 출력
 return os;
 }
 int main(void) {
 Point p(1,3);
 cout<<p; // operator<<(cout,p) 형태의 전역 오버로딩을 통해 가능하다.
 }

7. 인덱스 연산자.
 arr[i] => arr.operator[](i);

 // int& 같이 참조형 객체를 리턴하는 이유는 arr[0] =10; 같이 해당 배열에 값을 저장할수 있어야

하기 때문이다.
 int& Arr:operator[](int i) {
 return arr[i];
 }

 

8. 대입 연산자 오버로딩
 class Point {
 char* name; // 디폴트 오버로딩시 문제 방생
 }
 Point p1;
 Point p2 = p1; // 객체 생성시 이므로 Point p2(p1) 같이 복사생성자가 호출된다.

 Point p1;
 Point p2;
 p2 = p1; // 객체 생성이 아니므로 p2.operator=(p1) 이 되는것이다.

 // 디폴트일경우는 멤버대 멤버로 복사를 해줍니다.
 // 하지만 디폴트 복사생성자 처럼, 가벼운 복사가 이루어 지게 됩니다. 깊은 복사를 수행하려면
 // 반드시 오버로딩 하여 메모리 복사까지 수행해 주어야 합니다.

 // 아래와 같이 깊은 대입 연산자 오버로딩이 되도록 해주어야 한다.
 Point& Point::operator=(const Point& p) {
 delete[] p.name;// 읽어버릴 이름의 메모리를 해제해 주어야 합니다.

 // 이름에대한 메모리를 할당한다.
   this->name = new char[strlen(p.name)+1];
 strcpy(name,p.name);

 x = p.x;
 y = p.y;
 return *this;
 }