C++ Chapter 8.7 : this포인터와 연쇄 호출
카테고리: Cpp
태그: Cpp Programming
인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 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 속성
- 진짜 자기 자신(Calc 타입 객체)의 레퍼런스를 리턴하는 것이므로 실제 자기 자신 그 자체를 리턴한다.
- 7.3 다양한 리턴 값 포스트 참고
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기