C++ Chapter 8.7 : this포인터와 연쇄 호출

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!


chapter 8. 객체 지향의 기초 : this포인터와 연쇄 호출

🔔 this 포인터

this : 자기 자신(객체)의 주소를 담는 포인터다.

  • 포인터이므로
    • this -> 멤버 로 접근한다.
    • (*this).멤버 이렇게 간접참조로 접근할 수도 있다.
      • *this : 자기 자신(객체).
  • 원래 클래스 내에서 멤버들을 사용할 때 앞에 다 this->가 붙는데 생략되는 것이다.
class Simple
{
private:
	int m_id;

public: 
	Simple(int id)
	{
        
        setID(id);  // this->setID(id)와 같다.
        
        cout << m_id << endl; // cout << this->m_id << endl 와 같다.

        cout << this << endl;
	}
	void setID(int id) { m_id = id; }
	int getID() { return m_id; }
};

int main()
{
    Simple s1(1);  // 1,  0x7ffccf6ae898 출력
    Simple s2(2);  // 2,  0x7ffccf6ae89c 출력
    
    cout << &s1 << " " << &s2 << endl;  // 0x7ffccf6ae898 0x7ffccf6ae89c 출력

    return 0;
}
💎출력💎
1 
0x7ffccf6ae898
2 
0x7ffccf6ae89c       
0x7ffccf6ae898 0x7ffccf6ae89c 

출력 결과를 보면 this 값이 객체 주소값과 일치하는 것을 알 수 있다. 객체 s1가 생성될 때 실행했을 생성자가 this 값을 출력하는데 이는 &s1과 일치한다.

여담으로 위 코드에서 생성자 내부에 있는 setID 멤버 함수의 실행을 보고 객체를 생성하기도 전인데 어떻게 멤버함수를 벌써 생성자에서 실행할 수 있는지 헷갈렸다. 그러나 문제 없다! 객체가 생성되는 순간 생성자가 실행되는건 맞지만 생성자의 대괄호 범위는 이미 객체가 생성된 뒤에 실행되기 때문에 생성자 내에서 멤버 함수를 사용하는 것은 문제 없다.


🔔 연쇄 호출

연쇄 호출을 사용하지 않은 경우

#include <iostream>

using namespace std;

class Calc
{
private:
	int m_value;

public: 
	Calc(int init_value)     //생성자
		: m_value(init_value)
	{}
	void add(int value) { m_value += value;}
	void sub(int value) { m_value -= value; }
	void mult(int value) { m_value *= value; }
	void print() { cout << m_value << endl;}
};

int main()
{  /* 매우 번거롭다 ! */
	Calc cal(10);
	cal.add(10);
	cal.sub(3);
	cal.mult(4);
	cal.print();
	return 0;
}

멤버함수들을 연이어 호출할 때 계속 cal. 을 반복하여 쓰는게 번거롭다. 이때 this포인터를 이용한 연쇄호출을 사용하면 한 줄로 깔끔하게 요약할 수 있다.


연쇄 호출을 사용한 경우

#include <iostream>

using namespace std;

class Calc
{
private:
	int m_value;

public: 
	Calc(int init_value)     //생성자
		: m_value(init_value)
	{}
	Calc& add(int value) { m_value += value; return *this;}
	Calc& sub(int value) { m_value -= value; return *this; }
	Calc& mult(int value) { m_value *= value; return *this;}
	void print() { cout << m_value << endl; }
};

int main()
{  /* 매우 번거롭다 ! */
	Calc cal(10);
	cal.add(10).sub(1).mult(2),print();
	return 0;
}

각 멤버함수의 리턴 타입을 Calc& 객체 참조로 하고 이를 *this로, 즉 자기 자신(객체)를 리턴하니 cal.add(10).sub(1).mult(2),print(); 한 줄로 깔끔하게 실행할 수 있게 되었다. 위 코드는 사실 아래 코드의 과정과 동일하다.

Calc cal(10);
Calc & temp1 = cal.add(10); // temp1은 cal 메모리를 참조한다.
Calc & temp2 = temp1.sub(1); // temp1, temp2은 cal 메모리를 참조한다.
Calc & temp3 = temp2.mult(2); // temp1, temp2, temp3은 cal 메모리를 참조한다.
temp3.print();

일반 리턴

  • 그냥 Calc로 리턴 할 때. Calc add(int value){ return *this; }
    • Calc타입의 임시 변수에 자기 자신(Calc 타입 객체)이 복사된 후 그 임시 변수를 리턴한다.
    • 즉, 진짜 자기 자신의 객체를 리턴하는 것이 아닌 주소가 다른 또 다른 Calc 타입의 객체를 리턴하는 것.
      • 자기 자신이 복사 되었을 뿐.
    • 임시 변수는 지역 변수로서 함수가 수명이 다하며 같이 사라진다.
      • R-value 속성

참조 리턴

  • Calc &참조로 리턴할 때. Calc & add(int value){ return *this; }
    • 진짜 자기 자신(Calc 타입 객체)의 레퍼런스를 리턴하는 것이므로 실제 자기 자신 그 자체를 리턴한다.
      • 임시 변수에 복사하는 것 없이
    • 자기 자신 자체를 참조하는 Calc 레퍼런스를 리턴한다.
      • L-value 속성
  • 7.3 다양한 리턴 값 포스트 참고


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기


Cpp 카테고리 내 다른 글 보러가기

댓글 남기기