int main()
{
Point pos1(1, 2);
Point pos2 = pos1; // 복사생성자 호출
Point pos3(3, 4);
pos3 = pos1; // 대입 연산자 호출
}
따로 정의하지 않아도 디폴트 대입연산자가 정의되어 있다.
디폴트 대입 연산자의 경우 멤버 대 멤버 복사가 선언되어 있다.
만약 다음과 같이 멤버변수가 선언되있다면
class Point
{
private:
int num1;
int num2;
}
대입연산자는 다음과 같이 선언되있다.
class Point
{
public:
Point& operator=(const Point& ref)
{
num1 = ref.num1;
num2 = ref.num2;
return *this;
}
}
디폴트 대입 연산자는 멤버간 얕은 복사만 하기 때문에 깊은 복사가 필요한 경우 명시적으로 오버라이딩을 해야한다.
class Person
{
char * name;
int age;
public:
Person(const char* name, int age) : age(age)
{
int len = strlen(name)+1;
this->name = new char[len];
strcpy_s(this->name, len, name);
}
Person& operator=(const Person& ref) //깊은복사하는 대입연산자 오버로딩
{
delete []name; //메모리 누수를 막기위해 메모리 해제
int len = strlen(ref.name)+1;
name = new char[len];
strcpy_s(name, len, ref.name);
age = ref.age;
return *this;
}
delete []name;
을 먼저 해주는 이유는 대입 전에 원래 지정되있던 메모리를 사용할 일이 없기 때문에 삭제 해준다.
유도클래스의 대입연산자 오버로딩에서는 기초클래스의 대입연산자를 호출해줘야한다.
클래스 별로 자신의 멤버변수의 변경을 책임지는 것이 더 좋기 때문이다.
유도클래스의 디폴트 대입 연산자는 자동으로 기초클래스의 대입연산자를 호출해준다.
따라서 신경 안써도 된다.
class First
{
private:
int num1, num2;
public:
First(int num1, int num2) : num1(num1), num2(num2)
{
}
First& operator=(const First& ref)
{
num1 = ref.num1;
num2 = ref.num2;
return *this;
}
};
class Second : public First
{
private:
int num3, num4;
public:
Second(int a, int b, int c, int d) :First(a, b), num3(c), num4(d)
{
}
Second& operator=(const Second& ref)
{
First::operator=(ref); // 기초클래스의 대입연산자를 호출해줘야한다.
num3 = ref.num3;
num4 = ref.num4;
return *this;
}
};
BBB 클래스의 경우 이니셜라이저를 사용해 mem을 초기화하고
CCC 클래스는 생성자 몸체에서 mem의 초기화를 하고 있다.
복사 생성자 호출
AAA의 void 생성자 호출
대입 연산자 호출
이니셜라이저 사용시 함수호출이 하나 줄어든걸 볼 수 있다.