Coding/C & C++

C++ 연산자 오버로딩 2(대입, 배열의 인덱스, new/delete 연산자)

heyoon2j 2020. 3. 1. 01:36

 C++ 연산자 오버로딩 2(대입, 배열의 인덱스, new/delete 연산자)

ㆍ 대입 연산자 오버로딩

- 디폴트 복사 생성자와 마찬가지로 기본적으로 "디폴트 대입 연산자"가 있다.

=> 디폴트 대입 생성자는 멤버 대 멤버의 복사(얕은 복사)를 하기 때문에, 동적 할당 시 에러가 발생한다. 이를 해결하기 위해 깊은 복사를 하는 대입 연산자를 정의해야 한다.

- person1 = person2

     => person1.operator=(person2)

 

ex>

class Person

{

private:

     char* name;

     int age;

public:

     Person(char* myname, int myage) : age(myage)

     {

         name = new char[strlen(myname)+1];

         strcpy(name, myname);

     }

     Person& operator=(const Person& ref)

     {

         delete []name;

         name = new char[strlen(ref.name)+1];

         strcpy(name, ref.name);

         age=ref.age;

         return *this;

 

     }

 

}

* 상속 관계의 경우, 하위 클래스의 대입 연산자의 정의에서 명시적으로 상위 클래스의 대입 연산자 호출 문을 삽입해야 한다.

=> Person::operator=(ref);

 

 

ㆍ 배열의 인덱스 연산자 오버로딩

- 인덱스 연산자 오버로딩은 다음과 같이 해석된다.

     => arr[3] == arr.operator[](2);

 

ex>

typedef Person* PERSON_PTR;

 

class SimpleArray

{

private:

     PERSON_PTR *arr;

     int arrlen;

     SimpleArray(const SimpleArray& arr){}                       // private로 선언함으로써, 

     SimpleArray& operator=(const SimpleArray& arr){}      // 복사가 되지 않도록 함

public:

     SimpleArray(const int& len) : arrlen(len)

     {

          arr=new PERSON_PTR[len];

     }

     PERSON_PTR& operator[](const int& idx)                   // 객체 참조 값 반환(l-value)

     {

          if(idx>=arrlen || idx<0)

         {

              exit(1);

         }

          return arr[idx];

     }

    PERSON_PTR operator[](const int& idx)              // 객체 값 반환(r-value)

     {

          if(idx>=arrlen || idx<0)

         {

              exit(1);

         }

          return arr[idx];

     }

     ...

};

 

 

ㆍ new/delete 연산자 오버로딩

1. new 연산자 오버로딩

- 먼저 new 연산자가 하는 일은 다음과 같다.

 ① 메모리 공간 할당

 ② 생성자의 호출

 ③ 할당하고자 하는 자료형에 맞게 반환된 주소 값의 형 변환

 

- 여기서 ②, ③은 C++ 컴파일러가 처리하기로 약속했기 때문에, new 연산자 오버로딩을 통해서 ①에 해당하는 메모리 공간 할당만 오버로딩할 수 있다.

- new 연산자 오버로딩 함수는 static 함수로 간주된다.

- void* operator new (size_t size) {     ...     }

- void* operator new[] (size_t size) {     ...     }

     => 위와 같이 return 형: void* / 매개변수형: size_t 로 약속되어 있다(typedef unsigned int size_t)

 

ex>

void* operator new(size_t size)

{

     void* adr= new char[size];

     return adr

}

 

* 필요한 메모리 공간의 크기가 바이트 단위로 계산되어서 인자로 전달되기 때문에, char 단위로 메모리 공간을 할당해서 반환

 

 

2. delete 연산자 오버로딩

- 먼저 delete 연산자 실행 시 진행되는 일은 다음과 같다( ex> delete ptr; )

 ① ptr이 가리키는 객체의 소멸자를 호출

 ② delete 연산자 오버로딩 함수에 ptr 주소 값 전달 및 실행

 

- 소멸자는 오버로딩 된 함수가 호출되기 전에 호출이 되니 오버로딩 된 함수에서 메모리 공간의 소멸을 해야 한다

- delete 연산자 오버로딩 함수는 static 함수로 간주된다.

- void* operator delete (void* adr) {     ...     }

- void* operator delete[] (void* adr) {     ...     }

     => 위와 같이 return 형: void* / 매개변수형: size_t로 약속되어 있다(typedef unsigned int size_t)

 

ex>

void* operator delete(void* adr)

{

     delete []adr;     // delete []((char*)adr), 컴파일러에서 void* 형에 대상의 delete 연산을 허용 안 할 시

}