헤더파일

C++ 멤버함수 본문

C++

C++ 멤버함수

헤더파일 2020. 3. 9. 14:59

멤버함수 호출 원리

 

class Point
{
	int x = 0, y = 0;
public:
	void set(int a, int b) //set(Point* const this, int a...
	{
		x = a;
		y = b;
	}
};
 
int main()
{
	
	Point p1;
	Point p2;

	p1.set(10, 20); // set(&p1,10,20)
}

 

객체마다 함수를 할당하지 않는데 어떻게 p1의 x, y를 set하는지 알 수 있을까?

 

주석처럼 객체에 대한 포인터를 넘기기 때문에 가능합니다. 객체의 주소를 레지스터로 보내주고 함수 내부적으로는 레지스터의 값을 이용하여 동작합니다. 이런 동작을 this call 이라고 합니다.

 

class Point
{
	int x = 0, y = 0;
public:
	void set(int a, int b)
	{
		x = a;
		y = b;
	}
	static void foo(int a) // void foo(int a)
	{
		x = a;// this->x = a; -> 객체 주소가 없으므로 컴파일 에러
	}
};

 

 static 맴버함수는 인자로 객체의 주소 this를 받지 않습니다. 따라서 객체에 따라 특정되는 x, y값을 바꿀 수 없습니다.

 


맴버함수 포인터

class Dialog
{
public:
	void Close() {}
};

void foo() {}

int main()
{
	void(*f1)() = &foo;
 	void(*f2)() = &Dialog::Close;//컴파일 에러   
    
  	void(Dialog::*f3)() = &Dialog::Close; // ok.. 멤버 함수 포인터.
 }

 

맴버함수의 경우 this가 추가되야 하므로 일반적인 함수포인터로는 받을 수 없고 클래스 명을 추가한 Dialog:: 형태로 맴버함수를 받을 수 있습니다.

 

	Dialog dlg;
	//dlg.f3(); // dlg.Close()의 의미.. 하지만..f3이라는 멤버를 찾게된다.- error

	//dlg.*f3(); // ".*" : pointer to member operator
				// error. 연산자 우선순위 문제..

	(dlg.*f3)(); // ok.. dlg.Close();

사용할 때는 .*를 이용해 하는데 ()연산자가 .보다 우선순위가 앞서기 때문에 ()로 꼭 함수포인터를 묶어 줘야합니다.

 

객체가 포인터 일 경우 , 대신 ->를 사용하면 됩니다.

 

this call을 이용한 커스텀 스레드 클래스


#include <iostream>
#include <windows.h>
using namespace std;


// 라이브러리 내부 클래스
class Thread
{
public:

	void run()
	{
		CreateThread(0, 0, threadMain, (void*)this, 0, 0);
	}

	// 1. 아래 함수는 반드시 static 함수 이어야 합니다.
	// 2. 아래 함수는 this가 없다. 그래서 함수 인자로
	//    this를 전달하는 기술.

	static DWORD __stdcall threadMain(void* p)
	{
		Thread* const self = static_cast<Thread*>(p);

		self->Main(); // Main( self )

		//Main(); // 가상함수 호출
				// this->Main() => Main( this) 로 변해야 한다.

		return 0;
	}

	virtual void Main() // void Main(Thread* const this)
	{}
};






// 라이브러리 사용자 코드
class MyThread : public Thread
{
public:
	virtual void Main() { cout << "스레드 작업" << endl; }
};









int main()
{
	MyThread t;
	t.run();	// 이순간 스레드가 생성되어서 
				// 가상함수 Main()을 실행해야 합니다.
	getchar();
}

 

this map


c++ 로 콜백함수를 만들때는 static 맴버함수를 사용하게 되는데 이 경우 this 포인터가 중요해 집니다. 위에처럼 인자로 보낼 수 있지만 그럴 수 없다면 this 포인터를 자료구조에 보관해서 static 맴버함수에서 맴버함수에 접근하는 방법이 있습니다.

 

class Clock
{
	static map<int, Clock*> this_map;
	string name;
public:
	Clock(string n) : name(n) {}

	void start(int ms)
	{
		int id = ec_set_timer(ms, timerHandler );

		this_map[id] = this;
	}

	// 핵심 1. 아래 함수는 반드시 static 멤버 이어야 합니다.

	static void timerHandler(int id)
	{
		Clock* const self = this_map[id];

		//cout << name << endl;	// this->name
		cout << self->name << endl;
	}
};

map<int, Clock*> Clock::this_map;



int main()
{
	Clock c1("A");
	Clock c2("\tB");

	c1.start(1000); // 1000ms 에 한번씩 이름출력
	c2.start(500);  // 500ms 에 한번씩 이름출력

	ec_process_message();
}

'C++' 카테고리의 다른 글

C++ name mangling  (0) 2020.03.11
C++ 상수 멤버 함수 operator new 재정의  (0) 2020.03.11
캐스팅 정리  (0) 2019.11.17
스레드 프로그래밍  (0) 2019.11.06
C++ 정리2  (0) 2019.10.30
Comments