본문 바로가기

프로그래밍 언어/열혈 C++

11-1 연산자 오버로딩2

대입 연산자

디폴트 대입 연산자

  • 복사 생성자뿐 아니라 대입 생성자도 정의하지 않으면 디폴트 대입 연산자가 생성된다.
  • 디폴트 대입 연산자는 멤버대 멤버의 얕은 복사를 진행한다.
  • 연산자 내에서 동적 할당을 한다면, 깊은 복사를 해야 한다면 직접 정의해야 한다.

 

복사 생성자 호출 예시)

int main()
{
    Point pos1(5, 7);
    Point pos2 = pos1;
}

 

대입 생성자 호출 예시)

int main()
{
    Point pos1(5, 7);
    Point pos2;
    pos2 = pos1;
}

 

복사 생성자와 유사한 만큼 유사한 문제점(똑같다)과 유사한 해결책을 가지고 있다.

바로 문자열을 멤버로 가지게 될 때 대입한 객체와 대입된 객체가 하나의 문자열을 참조하는 상황이 발생한다.

 

해결책은

1. 대입되는 객체가 가지고 있던 문자열을 메모리 해제하고

2. 깊은 복사를 진행하면 된다.

Person& operator=(const Person& ref)
{
    delete[] name;
    this->name = new char[strlen(ref.name) + 1];
    strcpy(this->name, ref.name);
    age = ref.age;
    return *this;
}

 

상속에서 대입 연산자

  • 유도 클래스에서 대입연산자를 정의하지 않으면 기초 클래스의 대입연산자가 호출된다.
  • 유도 클래스의 대입 연산자가 기초 클래스의 대입 연산자를 호출하지 않으면 기초 클래스의 대입 연산자가 호출되지 않는다.

 

이니셜라이저를 통한 성능향상

#include <iostream>
using namespace std;

class AAA
{
private:
	int num;
public:
	AAA(int n=0): num(n)
	{  
		cout<<"AAA(int n=0)"<<endl;
	}
	AAA(const AAA &ref): num(ref.num)
	{  
		cout<<"AAA(const AAA & ref)"<<endl;
	}
	AAA & operator=(const AAA &ref)
	{
		num=ref.num;
		cout<<"operator=(const AAA &ref)"<<endl;
		return *this;
	}
};

class BBB
{
private:
	AAA mem;
public:
	BBB(const AAA & ref)
		: mem(ref)
	{  }
};

class CCC
{
private:
	AAA mem;
public:
	CCC(const AAA & ref)
	{
		mem=ref;
	}
};

int main(void)
{
	AAA obj1(12);
	cout<<"*********************"<<endl;
	BBB obj2(obj1);
	cout<<"*********************"<<endl;
	CCC obj3(obj1);
	return 0;
}

결과

AAA(int n=0)
*********************
AAA(const AAA & ref)
*********************
AAA(int n=0)
operator=(const AAA &ref)

이니셜라이저를 이용해서 초기화를 하면 선언과 동시에 초기화가 이뤄지는 형태로 바이너리 코드가 생성된다.

= AAA의 복사 생성자만 호출됨

 

대입을 이용해서 초기화를 하면 선언과 초기화가 별도의 문장으로 진행하는 바이너리 코드가 생성된다.

= AAA의 생성자와 대입 연산자가 호출됨