• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

증감연산자 오버로딩

24.03.18 23:49 작성 24.03.18 23:51 수정 조회수 140

1

안녕하세요 궁금한 것이 있어 여쭤봅니다

 

교수님께서 전위증가연산자 오버로딩 코드를 이렇게 짜셨습니다.

class Digit
{
private:
	int m_digit;

public:
	Digit(int digit = 0) : m_digit(digit) {}

	//prefix
	Digit& operator ++ ()
	{
		++m_digit;

		return *this;
	}

	friend ostream& operator << (ostream& out, const Digit& d)
	{
		out << d.m_digit;
		return out;
	}
};

아래는 main 함수 부분이고요

int main()
{
	Digit d(5);

	cout << ++d << endl;
	cout << d << endl;

	return 0;
}

여기 멤버함수로 구현이 돼있는데요

Digit& operator ++ ()
	{
		++m_digit;

		return *this;
	}

cout << ++d << endl; 에서 d를 만난다음 d가 ++연산자를 호출할텐데

 

++m_digit;이렇게 d인스턴스의 m_digit을 바로 1증가 시켜준다면 그냥 여기서 끝나면 되는 것 아닌가요?

 

인스턴스d가 호출한 ++연산자에서 인스턴스dm_digit을 직접 1증가 시켜줬는데,

 

위에서 operator ++ 왼쪽에 적혀 있는 리턴형인 Digit&과 리턴하는 값인 return *this;가 대체 무엇을 하는지 그 작동과정이 전혀 감이 안 잡혀서 구글링도 하고 그랬는데 원하는 것을 얻지 못한 거 같습니다 ㅠㅠ

자세한 설명 부탁드려도 될까요?

감사합니다

답변 2

·

답변을 작성해보세요.

2

Soobak님의 프로필

Soobak

2024.03.19

안녕하세요, 질문&답변 도우미 Soobak 입니다.

 

연쇄 호출(체이닝, Chaining)을 위함입니다.

연산을 수행한 후 객체 자신(*this)을 참조로 반환함으로써, 전위 증가 연산자가 표현식 내에서 사용될 때 해당 객체를 계속해서 사용할 수 있도록 합니다.

예를 들어, ++d 연산 후에 d 객체의 변경된 상태를 다시 사용하거나,
cout << ++d; 또는 ++(++d); 와 같이 연쇄적인 연산을 가능하게 하기 위한 방법입니다.

체이닝과 관련해서는, 강의 9.2 입출력 연산자 오버로딩 하기3:38 부분을 참고해보시면 이해에 도움이 되실 것 같습니다.

Echapper4님의 프로필

Echapper4

질문자

2024.03.19

답변 정말 감사합니다.

  1. ++(++d);의 경우에서 만약 제가 말한대로 반환 등을 쓰지 않고 오버로딩함수에서 ++m_digit만 수행하고 끝나게 되면

    ++(6)이 되는데 성립하지않고 cout에 의해 출력되지 못하는 형태라서 객체형인 자신을 반환해야된다는 맥락인가요?

     

  2. 객체자신의 반환의 의미에 대해 궁금한 것이 좀 더 있는데요,

    Digit& operator ++ ()
    {
    	++m_digit;
    
    	return *this;
    }

    에서 ++m_digit을 수행하게되면 인스턴스d가 가지고 있는 변수 m_digit는 6으로 변경이 되고, 즉슨 (객체)인스턴스d가 업데이트 된 다음

    다시 객체형태로 반환을 해줘야 하는데 객체d의 주소를 this포인터를 이용해 반환하는 것 같습니다.

    만약 제가 말한 객체 d의 주소를 반환(자기자신 객체를 반환)하는 과정이 이루어지는 게 맞다면

일단 return *this;에서 그 주소는 class digit이라는 타입의 공간의 주소니까

Digit& operator ++ ()
...

Digit&와 같이 리턴하는 주소가 Digit에 대한 것(형태)임을 알려주는 것이고 또한

그 주소를 복사하지않고 다른 별칭으로써 넘겨주겠다는 참조의 의미로 &를 사용한다. 라는 것이 옳은 이해인지 궁금합니다.

그리고 this포인터 자체가 자기자신 객체(인스턴스)의 주소를 머금고 있는 포인터인데 자기자신 객체의 주소를 넘겨준다면 그대로 this포인터를 사용하는 것이 옳지 않나요?
*this처럼 asterisk가 붙은 형태는 뭐가 다른지 궁금합니다.

미리 정말정말 감사합니다 ㅠㅠ

Soobak님의 프로필

Soobak

2024.03.19

질문 1)
: 네, 맞습니다.
++(++d); 와 같은 표현식에서, 만약 operator ++ 이 아무것도 반환하지 않는다면, 즉, void 타입이라면, 컴파일러는 ++(6) 과 같은 형태로 이해할 것이고, 이는 유효하지 않은 코드입니다.
++ 연산자는 객체나 변수에만 적용될 수 있으며, 6 과 같은 리터럴 값에는 적용되지 않기 때문입니다.

질문 2)
: 네, 중간에 이해 확인 차 말씀해주신 내용이 정확하십니다.

추가적으로, this 포인터는 현재 객체의 주소를 가리키는 내장 포인터입니다.
*this 는 이 포인터를 역참조하여, 주소가 아닌 객체 자체를 나타냅니다.
만약, this 포인터 자체를 반환한다면, 반환 타입은 포인터 타입이 되어야 합니다.
하지만, 연쇄 호출을 위해서 객체의 참조를 반환하기 위해 *this 를 사용하는 것입니다.

 

이해를 돕기 위해 조금 더 설명을 드려보면, Digit& 이라는 참조 반환은 'Digit 객체의 참조' 를 의미합니다.
참조를 반환하는 이유는 객체의 복사본을 만들지 않고, 원본 객체에 대한 접근을 제공하기 위함입니다. 따라서, Digit& 과 같이 연산 결과로 원본 객체 자체를 계속해서 사용하기 위해 복사본이 아닌, 원본 객체를 가리키는 참조로서 반환하는 것입니다.

 

이 때, operator ++ 의 오버로딩 구현부와 관련하여, ++m_digit 는 객체의 상태를 변경합니다.
이후 이루어지는 return *this; 에서 this 는 객체 자신의 주소를 가리키는 포인터이므로, *this 를 통해 이 포인터가 가리키는 객체 자체를 참조로서 반환합니다.
이를 통해 연쇄 호출이 이루어질 수 있게 됩니다.

Echapper4님의 프로필

Echapper4

질문자

2024.03.19

궁금증이 완벽하게 해소된 것 같습니다 감사해요..

어쩌면 지금 최고의 강의에서 수박님과 같은 최고의 qna도우미님과 함께 할 수 있다는 게 제게 최고의 축복이 아닌가 싶습니다 ㅠㅠ 감사해요

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.03.18

안녕하세요, 인프런 AI 인턴입니다.

Echapper4님, 질문해주신 전위 증감 연산자(++) 오버로딩에 대해 설명드리겠습니다. 주어진 메서드 Digit& operator ++ ()는 전위 증감 연산자(prefix increment operator)를 오버로딩하기 위해 멤버 함수로 정의된 것입니다. 이 함수는 기본적으로 인스턴스 자체의 값을 변경한 후, 해당 인스턴스의 참조(*this)를 반환합니다.

++m_digit; 라는 표현은 현재 객체의 m_digit 멤버 변수의 값을 1 증가시키는 역할을 합니다. 이후 return *this;는 이 연산을 수행한 객체 자신에 대한 참조를 반환하게 되는데, 이는 메서드 체이닝(method chaining)이나 표현식 내에서 해당 객체를 계속 사용할 수 있게 해줍니다. 예를 들어 (++d).someFunction(); 와 같은 코드가 가능하게 되며, 이는 연산 후에도 해당 객체의 다른 메서드를 바로 호출할 수 있다는 것을 의미합니다.

비슷한 문제로 과거에 다른 수강생분께서도 질문하셨던 적이 있으나, Echapper4님의 질문과는 약간 다른 맥락의 질문이었습니다. 전위 증감 연산자의 경우에 정확히 일치하는 기존 답변이 없는 것으로 보여집니다.

그러나 후위 증감 연산자(postfix increment operator)에 대한 질문 및 답변이 있는데, 이는 전위 증감 연산자와는 다소 차이가 있습니다. 후위 증감 연산자는 연산 전의 객체 상태를 저장해 두었다가, 연산 후에 그 저장된 상태를 반환해야 하기 때문에 더 복잡한 처리가 필요합니다.

제가 찾은 후위 증감 연산자와 관련된 기존 질문들은 다음과 같습니다. 아래 내용은 직접적인 해결 방법을 제시하기보다는 참고 자료로 사용하시는 것이 좋겠습니다.

  • [9.5] postfix operator overloading 실행시 쓰레기값 출력 문제: postfix 연산자를 오버로딩할 때 발생하는 쓰레기값 출력 문제에 대한 논의입니다. 이 글에서는 지역변수를 반환하지 말라는 점이 강조되어 있습니다. (바로가기)
  • [04:58] 연습문제 9-> 0, 0->9 로 돌아가게 하는 법: 숫자가 특정 범위를 넘어갈 때 값을 초기화하는 전위 증감 연산자에 대한 내용입니다. 이 글에 나와있는 코드는 전위 연산자의 예시로 참고하실 수 있습니다. (바로가기)
  • [03:05] postfix ++일 경우 리턴타입을 레퍼런스로 안해주는 이유: 리턴타입에 대한 핵심적인 내용이 담겨있습니다. 이 내용은 전위 연산자의 경우에도 일부 적용될 수 있습니다. (바로가기)

이 답변들은 return *this;의 의미에 대해 직접 답변하는 것은 아니지만, 연산자 오버로딩과 관련된 개념을 이해하는데 도움이 될 수 있습니다.

전위 증감 연산자의 return *this;에 대한 더 자세한 설명이 필요하시다면, 해당 강의의 질문&답변 게시판이나 자료실에서 추가적인 질문을 올리시는 것이 좋을 것 같습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.