(재공부 필요.)다중 상속과 함수 포인터.

보물창고·2023년 1월 23일
0

다시 공부 필요 240801

  • 재공부 필요.

다중 상속과 함수 포인터.

  • a와 b클래스를 다중상속하는 c클래스가 있다고 하자.

    • 메모리 구조는 이렇게 만들어짐.
  • 코드

    • 출력 결과를 확인해보면, 컴파일러가 알아서, pB의 주소값을 obj + sizeof(A) 만큼의 주소값을 출력하고 있는 것을 확인할 수 있음.
    • class C의 메모리 구조에 상속된 부모 크기만큼의 offset 이 적용된거다.
  • 여기서는 28 이랑 2C 인데 C는 12이므로 딱 4만큼의 차이가 있다.

class A 
{
public:
      int a; 
      //void fa()
      //{ cout << this << endl; }
};
class B 
{ 
    int b;
    //void fb()
    //{
    //    cout << this << endl;
    //}
};

class C : public A, public B
{
    int c;
};

int main()
{
    C obj;

    A* pA = &obj;
    B* pB = &obj;

    std::dec;
    cout << &obj << endl;
    cout << pA << endl;
    cout << pB << endl;

}

1. 다중 상속과 this 포인터 다른 예제

  • problem
    : 위의 클래스 a,b,c와 동일하고, a와 b에다가 fa() , fb() 라고 해서
    this를 출력하는 함수를 만들자.
    • 그리고, C obj를 선언하고, obj.fa() / obj.fb() 를 호출하자.

-> obj 객체를 통해서 기반클래스의 함수들을 호출했는데 this 포인터가 다르다는 것을 확인할 수 있다.

  • 결론
    : 여기까지만 보더라도 다중상속을 하게 되면, 각 기반클래스에 접근시
    파생클래스의 this 포인터와 offset 만큼이 기반 클래스마다 주어진다는 것을 확인할 수 있다.

2. 멤버 함수 포인터와 다중 상속 예제

  • 코드
    : 아래의 출력 결과를 보면, 왜?? 알아서 A , B 클래스의 this로 이동했는지를 알아보자.
class Base1 {
public:
    int a;
    void f1() {
        cout << this << endl;
    };
};

class Base2 {
public:
    int b;
    void f2() {
        cout << this << endl;
    };
};

class Derived : public Base1, public Base2 {
public:
    int c;
    void f3() {
        cout << this << endl;
    };
};

void main() {
    Derived obj;

    //아래 결과도 위의 샘플 코드와 동일한 형태로 출력된다.
    obj.f3(); // obj의 주소
    obj.f1(); // obj의 주소
    obj.f2(); // obj + sizeof(Base1) 주소

    void(Derived:: * fp)(); //Derived 클래스의 멤버 함수 포인터 선언

    //아래 결과도 위와 동일한 형태로 출력된다.
    fp = &Derived::f3;
    (obj.*fp)();
    fp = &Derived::f1;
    (obj.*fp)();
    fp = &Derived::f2;
    (obj.*fp)();
}
  • 실행결과

멤버 함수 포인터는 일반 함수 포인터와 다르게 함수의 주소를 저장하는 부분과 this 객체의 offset을 저장하는 부분으로 구분되어 있다. 그래서 멤버 함수 포인터 변수에 멤버 함수의 주소를 지정할 때 해당 함수가 어느 클래스에 속해 있는지에 따라 offset 크기도 같이 저장하게 된다.
따라서, Derived::f1 과 Derived::f3의 주소를 저장할 때는 offset값이 0으로, Derived::f2의 주소를 저장할 때는 sizeof(Base1)한 값이 offset으로 저장되어 멤버 함수 포인터 변수를 통해 함수를 호출할 때 this 값의 위치가 변경되어 들어가게 된다.

3. 멤버 데이터 포인터

  • 1번과 2번 예제에서 얻은 결과와 동일한 내용임.

  • problem
    : 멤버 함수 포인터를 이용해 클래스 Point의 멤버 데이터인 x,y를 참조한 후,
    주소값을 출력하라.

int Point::*p2 = &Point::x;
int Point::*p3 = &Point::y;

cout << p2 << endl;
cout << p3 << endl;
  • 결론
    : offset이 적용되는 것을 확인할 수 있음.
profile
🔥🔥🔥

0개의 댓글