I'm FanJae.

[C++ Intermediate] this call 본문

C++/Intermediate

[C++ Intermediate] this call

FanJae 2024. 9. 22. 19:49

1. this call

 

1-1. 멤버 함수의 의문점.

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);
}

- 멤버 데이터는 객체당 한 개씩 생성된다.

- 멤버 함수는 코드 메모리에 한 개만 만들어져 있다.

 

- 객체가 여러 개 생성되어도 멤버 함수는 한 개만 있다.

※ 함수 인자는 2개 (a, b) 밖에 없는데, x가 어떤 객체의 멤버 인지(pt1.x인지 pt2.x 인지) 어떻게 아는가?

 

1-2. 어떤 변환이 일어나는가?

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(10, 20); // set(&p1, 10, 20); 
    pt2.set(10, 20);
}

- 약간의 차이가 있지만 C++ 컴파일러에 의해서 이러한 형태로 변환된다.

- 멤버 함수 호출 시 객체의 정보(주소)가 같이 전달되는 것을 this call이라고 한다.

 

※ 실제 함수 인자가 전달되는 방식과 객체 주소가 전달되는 방식은 약간의 차이가 있다.

(32bit/64bit 환경, 컴파일러에 따라서도 차이가 존재한다.)

 

1-3. static 멤버 함수

class Point
{
   int x{0};
   int y{0};
public:
   void set(int a, int b)
   {
        x = a;
        y = b;
   }
   static void foo(int a)
   {
        x = a; // this->x = a로 변경할 수 없다.
               // error
   }
};

int main()
{
    Point pt1;
    Point pt2;
    
    pt1.set(10, 20);  // Point::set(&pt1, 10, 20)
    pt2.set(10, 20);  // Point::set(&pt2, 10, 20)
    
    Point::foo(10);   // Point::foo(10)
    pt1.foo(10);      // Point::foo(10)
}

- static 멤버 함수는 객체의 주소가 전달되지 않는다. 즉, this call이 아니다.

- 객체의 주소를 알 수 없기 때문에 x,y에 접근할 수 없다.

 

1-4. 정리

① non-static 멤버 함수 호출 시

- 객체의 정보(주소)가 같이 전달된다.

- this call

② static 멤버 함수 호출 시

- 객체의 정보(주소)가 같이 전달되지 않는다.

- this call이 아니다.

 

※ Aseembly Level에서 확인하면 인자로 보낸 값 이외에 추가로 한 값을 더 넣는 것을 볼 수 있다.  


2. 상수 멤버 함수와 this

class Object
{
public:
     void foo() {}
     void goo() const {}
};

int main()
{
    Object obj;
    obj.foo(); // ok
    obj.goo(); // ok
    
    const Object cobj;
    cobj.foo(); // error
    cobj.goo(); // ok
}

- 일반적으로 상수 객체는 상수 멤버 함수만 호출이 가능하다.

- 따라서 cobj는 foo()를 호출할 수 없다.

 

class Object
{
public:
     void foo(Object* this) {}
     void goo(const Object* this) {}
};

int main()
{
    Object obj;
    obj.foo(); // ok
    obj.goo(); // ok
    
    const Object cobj;
    cobj.foo(); // Object* this = &cobj;
    cobj.goo(); // const Object* this = &cobj;
    
}

- 즉, 컴파일러가 변경한 코드가 이와 같이 변경되는 것이다.

- 상수의 주소를 상수가 아닌 것을 가리키는 포인터에 담을 수 없다.

 

Comments