CPP/Cpp module

[cpp개념공부]클래스 멤버 포인터 , 함수 포인터(CPP Module02)

뜨거운 개발자 2023. 2. 28. 12:01

함수 포인터에 대한 개념과 멤버포인터 개념이 부족해서 한번 정리하고자 한다.

함수 포인터란

함수는 메모리 상에 있다는 것이 의아할 수 있다.

그러나 사실 프로그램 코드 자체는 메모리 상에 존재한다.

배열도 배열의 이름이 배열의 시작값을 가리키는 주소처럼, 함수 이름이 함수의 시작 주소 값을 의미한다.

함수 포인터의 정의 방법

(함수의 리턴형) (*포인터 이름)(첫번째 인자 타입, 두번째 인자 타입,....)

(만일 인자가 없다면 그냥 괄호 안을 비워두면 된다. 즉, int (*a)() 와 같이 하면 된다)

42과제에서 궁금증

그냥 함수처럼 사용하면 되는데..!

이번 과제에서는 왜 포인터로 해야할까?

멤버 포인터 연산자…!

The goal of this exercise is to use pointers to member functions.

이 연습의 목표는 멤버 함수에 대해 포인터를 사용해 보는 것이에요.

이 문단때문에 그런 것 같다

실제로는 & 없이 해도 되는 거 아닐까라고 생각했지만 아래에서 나오듯 이건 하나의 c++의 문법이다.

멤버포인터 연산자

멤버 포인터 변수

멤버 포인터 변수란

  • 특정 클래스에 속한 멤버만을 가리키는 포인터
  • 일반 포인터가 메모리상의 임의지점을 가리키는데 비해 멤버 포인터는 객체내의 한 지점만을 가리킨다.
  • 멤버 포인터도 일반 포인터와 같이 4byte이다.

형태 : 자료형 타입클래스 :: * 이름;

  • 대상의 타입이 필요
  • 특정 클래스 소속의 변수만을 가리킬 수 있어서 어떤 클래스의 멤버들을 가리킬 것인지 밝혀야 한다.
  • 타입이 다르거나 소속이 다르다면 가리킬수 없다! 즉 같은 소속이고 같은 타입인 경우 멤버 포인터 변수로 가리킬 수 있다.

*특정 클래스 소속의 변수만을 가리킬 수 있으므로 어떤 클래스의 멤버들을 가리킬 것인지도 밝혀야 하며 클래스 소속 뒤에 포인터임을 나타내는 구두점 와 변수의 이름을 적는다.

사용 예시

class MyClass
{
public:
		 int i,j;
     double d;
};

void main()
{
     MyClass A;//클래스 인스턴스 생성
     int MyClass::*pi; // 멤버포인터 변수 선언 자료형 타입클래스::*포인터명
     double MyClass::*pd;//멤버포인터 변수 선언 이번에는 형식이 다른 double형

     pi=&MyClass::i; //
     pi=&MyClass::j;
     pd=&MyClass::d;
}

멤버 포인터 변수를 초기화

  • 어떤 클래스에 속한 어떤 변수의 번지를 가리킬 것인지 멤버 포인터 변수= & Class::Member 식으로 대입
  • 이 대입식은 특정 변수의 번지를 가리키도록 하는 것이 아니라 클래스의 어떤 멤버를 가리킬 것인가만 초기화하는 것이므로 이 상태에서 멤버 포인터 변수에 대입되는 주소값이 결정되는 것은 아니다.
  • 다만 가리키는 멤버가 클래스의 어디쯤에 있는지 위치에 대한 정보만을 가질 뿐이다.
  • 클래스 전체를 하나의 작은 주소 공간으로 보고 클래스내의 멤버 위치를 기억하는 것이다.
  • 멤버 포인터 변수로 객체의 실제 멤버를 액세스할 때는 멤버 포인터 연산자라는 특수한 연산자가 필요하다.

멤버 포인터 연산자

  • .*연산자는 좌변의 객체에서 멤버 포인터 변수 mp가 가리키는 멤버를 읽는다.
  • Obj가 상수 객체가 아니고 mp가 상수가 아닌 데이터 멤버를 가리킨다면 Obj.*mp 자체는 왼쪽값(r-value)이므로 이 식을 왼쪽에 놓아 멤버 값을 변경하는 것도 물론 가능하다.
  • ->*연산자는 왼쪽의 포인터가 가리키는 객체에서 mp가 가리키는 멤버를 읽는다.
  • 두 연산자는 첫 번째 피 연산자가 객체인가 객체를 가리키는 포인터인가만 다를 뿐이며 기능적으로 거의 동일하다.

멤버 포인터 변수의 작동방식

멤버 포인터 변수가 실제로 어떻게 초기화되고 .* 연산자가 객체의 멤버를 어떻게 읽을 것인가는 컴파일러에 따라 구현 방식이 다를 것이다. 주로 클래스내의 멤버 위치인 오프셋을 기억해 두었다가 .*연산자가 적용될 때 객체의 오프셋을 대상체 타입만큼 읽는 방법을 쓴다.

728x90