일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- vector size
- discord bot
- new&delete
- constructor
- dynamic_cast
- c++ basic practice
- c++ multi chatting room
- std::endl
- base from member
- delete function
- pointer to member data
- return by reference
- virtual function
- virtual destructor
- increment operator
- conversion constructor
- std::vector
- virtual inheritance
- 더 지니어스 양면포커
- operator overloading
- member function pointer
- suffix return type
- placement new
- std::ostream
- this call
- C++
- vector capacity
- diamond inheritance
- std::cout
- virtual function table
- Today
- Total
I'm FanJae.
[C++] this, Reference return 본문
※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.
1. 객체를 어떻게 구분하는가?
#include <iostream>
class Point
{
int x{0};
int y{0};
public:
void set(int a, int b)
{
x = a;
y = b;
}
};
int main()
{
Point pt1;
Point pt2;
pt1.set(10, 20);
pt2.set(10, 20);
}
- 위와 같은 예제가 있다고 생각할때, 우리가 이와 같은 의문을 가질 수 있다.
- 멤버 데이터는 분명히 객체당 한 개씩 생성되고, 멤버 함수 또한 코드 메모리에 한 개만 만들어진다.
- 이는 객체가 여러 개 생성되도 그러하다. 대체 어떤 객체인지 어떻게 구분하는 것일까?
void set(int a, int b)
{
x = a;
y = b;
}
pt1.set(10,20);
pt2.set(10,20);
- pt1,pt2에서 set() 호출할때 이들의 정보를 set에 준 적이 없다.
- 이들을 정확히 구분하려면 객체 pt1의 정보(주소)도 분명히 전달받아야 구별이 가능할 것이다.
2. this
#include <iostream>
class Point
{
int x{0};
int y{0};
public:
void set(Point* this,int a, int b)
{
this->x = a;
this->y = b;
}
};
int main()
{
Point pt1;
Point pt2;
pt1.set(&pt1,10, 20);
pt2.set(&pt2,10, 20);
}
- 실제로 이렇게 변환되지는 않지만, 멤버 함수 호출 시 위와 같이 객체의 주소가 같이 전달된다.
- 이러한 것을 this call 이라고 한다.
- this는 멤버 함수 안에서 사용가능한 키워드로, 해당 멤버 함수를 호출할 때 사용한 객체의 주소이다.
※ 객체 생성 여부와 별개로 메모리에 할당되는 static member function에서는 this를 사용할 수 없다.
2-1. 어셈블리어 레벨에서 확인
- 우리가 실질적으로 보낸 것은 2개지만, 1개의 인자를 더 사용하는 것을 확인이 가능하다.
2-2. this가 사용되는 경우
- 멤버 데이터라는 것을 명확히 하고 싶을때 사용할 수 있다.
- 또한, 멤버 함수가 this 또는 *this를 반환하면, 멤버 함수를 연속적으로 호출할 수 있다.
class Counter
{
int count{0};
public:
void reset(int count = 0)
{
this->count = count;
}
Counter* increment()
{
++count;
return this;
}
Counter& decrement() // 참조(Reference)로 반환해야 함에 유의하라
{
--count;
return *this;
}
};
int main()
{
Counter c;
c.increment()->increment()->increment();
c.decrement().decrement().decrement();
}
※ 주의할 점은 *this를 반환하는 경우 반드시 참조(Reference)로 반환해야 한다.
※ 이유가 상당히 중요하므로 아래에서 한번 다룬다.
2-3. Reference Return 예시
Reference Return을 하는 경우의 예시
- 이를 사용하고 있는 대표적인 케이스가 바로 std::cout이다.
- std::cout << "A" << "B" << "C";의 경우 std::cout.operator<<("A") 가 구현된 것이다.
- 이후, return *this 즉, std::cout가 바로 반환되기 때문에 위와 같이 사용이 가능한 것이다.
3. Reference Return
- 시작에 앞서 아래 그림을 통해 다시 한번 기억해보고자 한다.
- Call by value는 객체의 복사본을 생성한다. f1에서 p1을 parameter로 정의시,객체가 생성될때 복사본을 만든다.
- 반면, Call by Reference는 객체의 복사본이 아닌 기존 객체의 별칭(Alias)를 한다.
struct Point
{
int x;
int y;
};
Point pt = {1, 2};
Point f1() // return by value
{
return pt;
}
Point& f2() // return by reference
{
return pt;
}
int main()
{
// f1().x = 10; // 리턴용임시객체.x = 10
f2().x = 10; // pt.x = 10 ok.
}
- 함수가 객체를 값으로 반환하는 경우에는 리턴용 임시객체(temporary)가 생성되어 반환된다.
- return 용도로 생성된 임시객체(temporary)는 함수를 호출하는 문장의 끝에서 파괴된다.
- 따라서 등호의 왼쪽에 놓일 수 없다. 즉, rvalue이다.
Point pt = {1,2};
Point f1()
{
return pt;
}
- 즉, 이건 얼핏 보기에 큰 문제가 없어보이지만, 실제로는 pt 그 자체를 반환하는게 아니다.
- pt와 동일한 다른 임시 객체를 반환하게 된다.
3-1. temporary의 생성과 파괴
- 생성될 때 복사 생성자가 호출되고, 파괴 될 때 소멸자가 호출된다.
#include <iostream>
class Point
{
public:
int x;
int y;
Point(int a, int b) : x(a), y(b)
{
}
Point(const Point& pt) : x(pt.x), y(pt.y)
{
std::cout << "Test\n";
}
};
Point pt{1,2};
Point f1()
{
return pt;
}
Point& f2()
{
return pt;
}
int main()
{
std::cout << f1().x << std::endl;
std::cout << "------------" << std::endl;
std::cout << f2().x << std::endl;
}
- 이와 같이 복사 생성자가 실행되는 것을 확인할 수 있다.
※ return by value 에서는 리턴용 임시객체가 반환되는 반면, return by reference는 리턴용 임시객체가 생성되지 않는다.
- 복사 생성자에 대해서는 다음 포스트에 다뤄보고자 한다.
- 따라서, 이 내용에서 복사 생성자에 대한 얘기는 이후 포스트를 수정하여 재정리할 것이다.
'C++ > Basic' 카테고리의 다른 글
[C++] Inheritance(상속) (0) | 2024.08.20 |
---|---|
[C++] Copy Constructor (0) | 2024.08.19 |
[c++] const member function, mutable (0) | 2024.08.17 |
[C++] Static Member (0) | 2024.08.16 |
[C++] Explicit Constructor (0) | 2024.08.14 |