Notice
Recent Posts
Recent Comments
Link
헤더파일
C++ 멤버함수 본문
멤버함수 호출 원리
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 |