공부/C || C++

C++ 대입 연산자는 왜 void로 선언하면 안될까? 반환 타입에 왜 참조자를 붙여야 할까?

sudo 2021. 7. 18. 02:54
class AAA
{

public:
	int x;
	int y;

public:
	AAA(int _x, int _y) : x(_x), y(_y) {};
}

위와 같은 클래스가 있을 때 대입 연산자를 어떻게 작성할까? 대부분 아래와 같이 작성 할것이다.

AAA& operator=(const& AAA aaa)
{
    x = aaa.x;
    y = aaa.y;
    
    return *this;
}

여기서 의문점이 드는것은 두가지였다. 첫번째는 그냥 대입만 하면 되니까 void 리턴 타입으로 하면 되지 않을까? 였다.

첫번째 의문은 나와같은 의문을 가진 사람의 stackoverflow 질문에 대한 답변에서 찾을 수 있었다.

https://stackoverflow.com/questions/42335200/assignment-operator-overloading-returning-void-versus-returning-reference-param

결론부터 이야기하면 void 리턴타입으로 대입 연산자를 만드는게 가능은 하지만, 그렇게 하면 A = B = C같은 chain of assignment가 안되기 때문에 객체를 리턴해야 하는 것이다. B = C를 하고 객체를 리턴해야 그 객체를 다시 A에 할당해줄 수 있을 것이다.

 

두번째 의문은 microsoft docs에 아래와 같은 설명에서 답을 찾을 수 있었다.

https://docs.microsoft.com/en-us/cpp/cpp/assignment-operators?view=msvc-160

해석해보면 대입 연산자는 좌측값(예를 들어, x = 4 표현식에서 x를 의미)을 리턴한다. 즉 대입 연산자는 항상 lvalue를 리턴해야 하는데 그냥 값으로 리턴하면 rvalue이기 때문에 참조자를 붙여서 lvalue로 만들고 리턴한다는 것이다. 내가 이해한 바로는 (x = (y = z)) 연산에서 y = z를 수행하고 y = z라는 표현식은 사라진다(rvalue) 하지만 y라는 변수 자체는 살아서 지속돼서(lvalue) x에 값을 전달해줄 수 있다. 그래서 lvalue를 리턴해야 한다는 것 같고 그래서 레퍼런스를 하나 붙여줘서 리턴하는 것 같다.

 

대입 연산자 외에도, +=, -=, *= 와 같은 연산 후 대입해주는 연산자 오버로딩에도 참조자를 붙여줘야 한다고 한다.

https://en.cppreference.com/w/cpp/language/operator_assignment#Builtin_direct_assignment