this

클래스의 멤버 함수를 호출할 때 C++는 어떻게 호출할 객체(인스턴스)를 찾는가

class A
{
public:
    int id;
    
    A(int parm) { SetID(parm); }
    void SetID(int parm) { id = parm; }
};

int main()
{
    A a(1);
    a.SetID(2);
    cout << a.id << endl;
}

a.SetID(2)는 하나의 int 인자를 가지고 호출되는것 처럼 보이지만,

실제로는 simple.SetID(&a, 2);  a의 주소값과 int 두 개의 인자를 가지고 호출한다.

첫번째 파라미터로 전달된 a의 인스턴스의 주소는 이름이 this인 포인터 변수에 저장이 된다.

이 this는 지역변수이다.

 

이 과정은 컴파일러에 의해서 추가된다.

 

컴파일러 입장에서 본다면

class A
{
public:
    int id;
    
    A(A* const this, int parm) 
    { 
        this->SetID(parm); 
    }
    
    void SetID(A* const this, int parm) 
    { 
        this->id = parm; 
    }
};

int main()
{
    A a(&a, 2);
}

다음과 같이 컴파일 되는것이다.

. 은 클래스의 멤버를 직접 접근

->은 포인터를 통해 멤버를 접근

this는 포인터 변수이므로 ->를 사용해 멤버변수에 접근하는것

 

---------------------------------------------------------------------

그런데 this포인터를 굳이 만들필요가있었을까?

 

클래스의 멤버변수들은 객체가 만들어질때마다 메모리에 할당된다.

하지만 함수와 같이 반복호출하고 크기가 큰 것들은 메모리에 할당하면 낭비가 심하다

 

예를들어 A클래스 인스턴스 a1 a2 a3 a4 a5가 있다고하면 이들은 모두 각각 id라는 멤버변수를 가져 메모리에 할당된다.

하지만 생성자나 SetID함수 경우, 인스턴스 모두 공통적으로 사용할 수 있고 똑같은 함수를 굳이 메모리에 인스턴스마다 할당할 필요가 없기때문에 함수는 한번만 메모리에 할당하고 인스턴스의 주소값을 this 포인터에 보내주어 어떤 인스턴스가 함수를 호출하였는지 알게하는것이다. 

https://gdnn.tistory.com/185

----------------------------------------------------------------------

 

연산자 오버로딩

기존의 연산자를 새로 재정의하여 사용자 정의 클래스로 사용하는 것

오버로드 된 연산자는 함수로 구현된다.

int main()
{
    A a1(2);
    A a2(3);
    
    A a3 = a1 + a2; 
}

A클래스의 a1의 id와 a2의 id를 더한 a3 인스턴스를 만들고싶다.

그렇지만 A클래스의 덧셈은 정의되어있지않아 오류가 날 것이다.

class A
{
private:
    int id;

public:
    A(int parm)
    {
        this->SetID(parm);
        
    }

    void SetID(int parm)
    {
        this->id = parm;
    }

    A operator + (A& a)
    {
        this->id += a.id;
        return A(id);
    }

    friend ostream &operator<<(ostream &, const A &);
};

ostream &operator<<(ostream &os, const A &a)
{
    os << "id: " << a.id;
    return os;
}

int main()
{
    A a1(2);
    A a2(3);

    A a3 = a1 + a2;
    cout << a3;
}

함수의 이름을 operator로 사용함으로써 컴파일러에게 연산자 오버로드 함수인것을 명시한다.
a1이 오버로드된 + 연산자 함수를 호출하였고, a2가 A &a 인자값으로 넘겨받아지는 것이다.

또한 cin, cout의 << 연산자 >> 연산자 오버로딩도 가능하다. (cout은 ostream 타입의 객체)

우선 ostream 클래스 내부라고한다.

ostream& operator<<(bool& val);
ostream& operator<<(short& val);
ostream& operator<<(unsigned short& val);
ostream& operator<<(int& val);
ostream& operator<<(unsigned int& val);
ostream& operator<<(long& val);
ostream& operator<<(unsigned long& val);
ostream& operator<<(float& val);
ostream& operator<<(double& val);
ostream& operator<<(long double& val);
ostream& operator<<(void* val);

A객체의 private 멤버인 id에 접근 할 수 있도록 A 클래스 내부에 friend 함수를 지정해 주었고, ostream과 A클래스의 인스턴스의 주솟값을받아 id를 출력하도록 재정의해주었다.

 

 

 

+ Recent posts