C++/summary

연산자 중복

gandus 2010. 6. 11. 11:27

sum = x + y + z  이것을 구현하자.

멤버 함수로 구현.
비멤버 함수(프랜드 함수)로 구현   // 인자 갯수의 차이가 난다.


원점 벡터 예제

private:

           double x, y;

public:

           Vector(double x, int double){

                     this->x = x;

                     this->y = y;

           }

 

반환형 operator연산자(매개 변수 목록)

{

....// 연산 수행

}

 

() Vector operator+(const Vector&, const Vector&);  // 반환값이 클래스.
                                                                  // 공개된 멤버만 접근이 불가해서, 프렌드로 구현하는게 좋다.

실질적인 예를 살펴보자



비멤버 함수(레퍼런스)로 구현.


class Vector

{

private:

           double x, y;

public:

           Vector(double x, double y){

                     this->x = x;

                     this->y = y;

           }

           void display()

           {

                     cout << "(" << x << ", " << y << ")" << endl;

           }

           friend Vector operator+(const Vector& v1, const Vector& v2);  // 순서가 중요하다. // 외부정의
};

 

 

Vector operator+(const Vector& v1, const Vector& v2)  

{

           Vector v(0.0, 0.0);    // 임시객채를 생성해서

           v.x = v1.x + v2.x;

           v.y = v1.y + v2.y;

           return v;             // 반환

}         
- > 이것을 간결하게

           return Verctor(v1.x + v2.x ,  v1.y + v2.y); // 이름없는 객채를 반환해도 가능.
int main()

{

           Vector v1(1, 2), v2(3, 4);

           Vector v3 = v1 + v2;   // 반환된 객채를 불러온후 그 다음에 v3에 정의를 한다.
                                       // 복사 생성자는 2번 호출된다, 반환될때, 그리고 v3를 정의할때.

           v3.display();

           return 0;

}



멤버 함수로 구현

class Vector

{

private:

           double x, y;

public:

           Vector(double x, double y){

                     this->x = x;

                     this->y = y;

           }

           Vector operator+(Vector& v2)

           {

                     Vector v(0.0, 0.0);

                     v.x = this->x + v2.x;

                     v.y = this->y + v2.y;

                     return v;

           }         

 

void display()

           {

                     cout << "(" << x << ", " << y << ")" << endl;

           }

};

int main()

{

           Vector v1(1.0, 2.0), v2(3.0, 4.0);

           Vector v3 = v1 + v2;

           v3.display();

           return 0;

}

 
-> 프로토 타입을 어떻게???? 시험


Vector& operator= (const Vector& v2)  // 이것은 얕은 복사이다.
{
   this->x = v2.x;
   this->y = v2.y;   
   return *this;      // 레퍼런스를 반환한다,  자신을 반환해야지 연속적으로 사용가능하다.
}        - > 디폴트로 프로그램에서 만들어 준다.


레퍼런스를 반환하는 이유??

- 연쇄적으로 호출하도록
   v1 = v2 = v3 - > v2= v3 -> 레퍼런스로 리턴  - > v1 = v2 
- 만약 값으로 반환된다면 다음으로 반환되지 않는다.

cout<< v1 << v2 << v3; //연쇄적으로
-> v1 호출후 반환되는 값은?  cout 이 되야지 v2 호출, v3 호출이 가능하다.

깊은 복사를 예제로 살펴보면

class MyArray {

           friend ostream& operator<<(ostream &, const MyArray &); // 출력 연산자 <<

private:

           int *data;                     // 배열의 데이터

           int size;            // 배열의 크기

public:

           MyArray(int size = 10);    // 디폴트 생성자

           ~MyArray();                            // 소멸자

           int getSize() const;                    // 배열의 크기를 반환

           MyArray& operator=(const MyArray &a);   // = 연산자 중복 정의

           int& operator[](int i);      // [] 연산자 중복: 설정자

};

 

MyArray::MyArray(int s) {

           size = (s > 0 ? s : 10);    // 디폴트 크기를 10으로 한다.

           data = new int[size];      // 동적 메모리 할당

           for (int i = 0; i < size; i++)

                     data[i] = 0;           // 요소들의 초기화

}

MyArray::~MyArray() {

           delete [] data;                       // 동적 메모리 반납

           data = NULL;

}

MyArray& MyArray::operator=(const MyArray& a) {

           if (&a != this) {                        // 자기 자신인지를 체크

                     delete [] data;                         //  기존의 데이터를 동적 메모리 반납

                     size = a.size;                           // 새로운 크기를 설정

                     data = new int[size];                 // 새로운 동적 메모리 할당

                     for (int i = 0; i < size; i++)

                                data[i] = a.data[i];          // 데이터 복사

           }

           return *this;                                      // a = b = c와 같은 경우를 대비

}                                                               // 자신이면, 그냥 자신을 반환한다.

 

int MyArray::getSize() const

{

           return size;

}

int& MyArray::operator[](int index) {

           assert(0 <= index && index < size);         // 인데스가 범위에 있지 않으면 중지

           return data[index];

}

// 프렌드 함수 정의

ostream& operator<<(ostream &output, const MyArray &a) {

           int i;

           for (i = 0; i < a.size; i++) {

                     output << a.data[i] << ' ';

           }

           output << endl;

           return output;                         // cout << a1 << a2 << a3와 같은 경우 대비

}

 

 

int main()

{

           MyArray a1(10);

           a1[0] = 1;

           a1[1] = 2;

           a1[2] = 3;

           a1[3] = 4;

           cout << a1 ;

           return 0;

}                   

 
-> 기존의 참조하던 동적할당을 해제, 그 다음에 새롭게 동적할당을 이용한다.
-> 자신을 참고할때는 예외





클래스 빅3 : 동적할당데이터를 가질경우

 - 소멸자 : 동적할당 해제
 - 복사 생성자 : 깊은 복사(초기화) - 한번만 가짐
 - = 연산자 함수 : 깊은 복사(대입) - 만들어진후 계속 값이 바뀜



==
연산자 중복

 - 반환값은 bool 타입이 되야한다.


// 프렌드 함수로 정의

bool operator==(const Vector &v1, const Vector &v2)

{

    return v1.x == v2.x && v2.y == v2.y;

}

// 프렌드 함수로 정의

bool operator!=(const Vector &v1, const Vector &v2)

{

    return !(v1 == v2); // 오버로딩된 == 연산자를 이용

}

 


<<
>> 연산자 중복

cout<< 3 << 3.14 << 'a'<< "hello";

cout<< v;  = >


class Vector

{

private:

           double x, y;

public:

           Vector(double x, double y){

                     this->x = x;

                     this->y = y;

           }

           Vector operator+(const Vector& v2) const

           {

                     Vector v(0.0, 0.0);

                     v.x = this->x + v2.x;

                     v.y = this->y + v2.y;

                     return v;

           }         

           friend ostream& operator<<(ostream& os, const Vector& v);
};

 

ostream& operator<<(ostream& os, const Vector& v)

{

           os << "(" << v.x << "," << v.y << ")" << endl;

           return os;

}

int main()

{

           Vector v1(1.0, 2.0), v2(3.0, 4.0);

           Vector v3 = v1 + v2;

           cout << v1 << v2 << v3;

           return 0;

}

 

 

 

연산자 중복시 주의할 점


 

  • 새로운 연산자를 만드는 것은 허용되지 않는다.
  • :: 연산자, .* 연산자, . 연산자, ?: 연산자는 중복이 불가능하다.   // :: 클래스 멤버,  . 멤버 변수에, ? 삼항연산자 중복 불가
  • 내장된 int형이나 double형에 대한 연산자의 의미를 변경할 수는 없다.
     -  int operator+ (int a, int b)
          {return a + b + 1  } // 이것이 불가능하다, +1하면 심각한 문제.
  • 연산자들의 우선 순위나 결합 법칙은 변경되지 않는다.
  • 만약 + 연산자를 오버로딩하였다면 일관성을 위하여 +=, -= 연산자도 오버로딩하는 것이 좋다.
  • 일반적으로 산술 연산자와 관계 연산자는 비멤버 함수로 정의한다. 반면에 할당 연산자는 멤버 함수로 정의한다.


    1. 벡터를 나타내는 Vector 클래스에 - 연산자를 중복하라.

    2. 벡터를 나타내는 Vector 클래스에 += 연산자를 중복하라.

    3. 문자열을 나타내는 String 클래스를 작성하고 << 연산자를 중복하라.

     

 

타입 변환

 
생성자 중복정의
 - 기본 생성자
- 복사 생성자
- 반환생성자
- 다중인자 생성자



변환 생성자

class Book

{

private:

           int isbn; // 책의 ISBN

           string title;        // 책의 제목

public:

           Book() { // 생성자

                     isbn = 0;

                     title = “unknown";

           }

           Book(int isbn)    // 다른 타입이라서 변환 생성자.

                     this->isbn = isbn;

                     this->title = "unknown";

           }

           void display() {

                     cout << isbn << ":" << title << endl;

           }

};

 

int main()

{

           Book b1 = 9782001;       // int 타입을 Book 타입에 대입

                                // 정수형을 객체에 대입한 것 처럼, 그래서 변환 생성자

           b1.display();

           b1 = 9783001;    // 가능

           b1.display();

           return 0;

}

 

 

 

변환 연산자.

 

 

#include <iostream>

#include <string>

using namespace std;

class Book

{

private:

           int isbn;

           string title;

public:

           Book(int isbn, string& title) {

                     this->isbn = isbn;

                     this->title = title;

           }

           Book(int isbn) {

                     this->isbn = isbn;

                     this->title = "unknown";

           }

           operator int() const

           {

                     return isbn;

           }

 

void display() {

                     cout << isbn << ":" << title << endl;

           }

};

bool check(int isbn)

{

           cout << isbn << endl;

           return true;

}

int main()

{

           Book b1 = 9782001;       // 변환 생성자 실행!

           b1.display();

           int isbn = b1;               // 변환 연산자 실행!

           cout << isbn << endl;

           check(b1);                    // 변환 연산자 실행!

           return 0;

}