자료 저장소

# 디폴트 대입연산자

■ 디폴트 복사 생성자의 특징

- 정의하지 않으면 디폴트 복사 생성자가 삽입된다.
- 디폴트 복사 생성자는 멤버 대 멤버의 복사(얕은 복사)를 진행한다.
- 생성자 내에서 동적 할당을 한다면, 그리고 싶은 복사가 필요하다면 직접 정의해야 한다.

■ 디폴트 대입 연산자의 특징

- 정의하지 않으면 디폴트 대입 연산자 삽입된다.
- 디폴트 복사 생성자는 멤버 대 멤버의 복사(얕은 복사)를 진행한다.
- 생성자 내에서 동적 할당을 한다면, 그리고 싶은 복사가 필요하다면 직접 정의해야 한다.

※ 이미 생성 및 초기화가 진행된 객체에 대해 멤버대 멤버의 깊은 복사를 진행할 경우 직접 정의해야 한다.

pos1=pos2 → pos2.operator=(pos1)// 이와 같이 해석된다.

■ 디폴트 대입 연산자의 문제점

Person& Person::operator=(const Person& ref) 
{
name=ref.name;
age=ref.age;
return *this;
}
- 위 코드에서는 현재 객체의 멤버가 ref객체의 멤버를 대입하고 있는데 두 객체가 같은 문자열을 참조하게된다.
- 또한 현재 가리키던 문자열의 주소를 잃어버리게 되고 이때 메모리 누수가 발생한다.
- 얕은 복사로 인해서, 객체 소멸과정에서 지워진 문자열을 중복 소멸하는 문제가 발생한다.

■ 디폴트 대입 연산자의 문제점 해결
Person& Person::operator=(const Person& ref) 
{
delete []name;
int len=strlen(ref.name)+1;
name= newchar[len];
strcpy(name, ref.name);
age=ref.age;
return *this;
}

- 깊은 복사가 진행되도록 정의하고, 메모리 누수를 막기 위해 메모리를 해제 후 다시 할당 한다.

■ 상속 구조에서 대입 연산자 호출

- 대입연산자는 생성자가 아니다. 유도 클래스의 생성자에는 아무런 명시를 하지 않아도 기초 클래스의 생성가 호출
되지만, 유도 클래스의 대입 연산자에는 아무런 명시를 하지 않으면, 기초 클래스의 대입 연산자가 호출되지 않는다.
디폴트 대입 연산자의 경우 유도 클래스의 디폴트 대입연산자가 호출될 경우 기초 클래스의 대입 연산자까지 호출
하지만 대입 연산자를 정의할 경우 명시적으로 기초 클래스의 대입 연산자 호출문을 삽입하지 않으면, 기초 클래스의
대입 연산자는 호출되지 않아서, 기초 클래스의 멤버변수는 멤버 대 멤버의 복사대상에서 제외된다.


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

일반적인 배열은 접근에 대한 경계검사를 진행하지 않기때문에 경계검사 기능을 추가하여 오버로딩한다.




■ 객체의 저장을 위한 배열 클래스의 정의

(1) Point 객체를 저장하는 배열 기반의 클래스

#include <iostream> 
#include <cstdlib>
usingnamespacestd;

class Point
{
private:
int xpos, ypos;
public:
Point(int x=0, int y=0) : xpos(x), ypos(y) { }
friend ostream& operator<<(ostream& os, const Point& pos);
};

ostream& operator<<(ostream& os, const Point& pos)
{
os<<'['<<pos.xpos<<", "<<pos.ypos<<']'<<endl;
return os;
}

class BoundCheckPointArray
{
private:
Point * arr;
int arrlen;

BoundCheckPointArray(const BoundCheckPointArray& arr) { }
BoundCheckPointArray& operator=(const BoundCheckPointArray& arr) { }

public:
BoundCheckPointArray(int len) :arrlen(len)
{
arr=new Point[len];
}
Point& operator[] (int idx)
{
if(idx<0 || idx>=arrlen)
{
cout<<"Array index out of bound exception"<<endl;
exit(1);
}

return arr[idx];
}
Point operator[] (int idx) const
{
if(idx<0 || idx>=arrlen)
{
cout<<"Array index out of bound exception"<<endl;
exit(1);
}

return arr[idx];
}
int GetArrLen() const
{
return arrlen;
}
~BoundCheckPointArray()
{
delete []arr;
}
};

int main(void)
{
BoundCheckPointArray arr(3);
arr[0]=Point(3, 4);
arr[1]=Point(5, 6);
arr[2]=Point(7, 8);

for(int i=0; i<arr.GetArrLen(); i++)
cout<<arr[i];

return0;
}


(2) 객체의 주소값을 저장하는 배열 기반의 클래스
#include <iostream> 
#include <cstdlib>
usingnamespacestd;

class Point
{
private:
int xpos, ypos;
public:
Point(int x=0, int y=0) : xpos(x), ypos(y) { }
friend ostream& operator<<(ostream& os, const Point& pos);
};

ostream& operator<<(ostream& os, const Point& pos)
{
os<<'['<<pos.xpos<<", "<<pos.ypos<<']'<<endl;
return os;
}

typedef Point * POINT_PTR;

class BoundCheckPointPtrArray
{
private:
POINT_PTR * arr;
int arrlen;

BoundCheckPointPtrArray(const BoundCheckPointPtrArray& arr) { }
BoundCheckPointPtrArray& operator=(const BoundCheckPointPtrArray& arr) { }

public:
BoundCheckPointPtrArray(int len) :arrlen(len)
{
arr=new POINT_PTR[len];
}
POINT_PTR& operator[] (int idx)
{
if(idx<0 || idx>=arrlen)
{
cout<<"Array index out of bound exception"<<endl;
exit(1);
}

return arr[idx];
}
POINT_PTR operator[] (int idx) const
{
if(idx<0 || idx>=arrlen)
{
cout<<"Array index out of bound exception"<<endl;
exit(1);
}

return arr[idx];
}
int GetArrLen() const
{
return arrlen;
}
~BoundCheckPointPtrArray()
{
delete []arr;
}
};

int main(void)
{
BoundCheckPointPtrArray arr(3);
arr[0]=new Point(3, 4);
arr[1]=new Point(5, 6);
arr[2]=new Point(7, 8);

for(int i=0; i<arr.GetArrLen(); i++)
cout<<*(arr[i]);

delete arr[0];
delete arr[1];
delete arr[2];
return0;
}

댓글 로드 중…

최근에 게시된 글