C++ 클래스 오버라이드좀 시켜주세요!
글쓴이: MyAbby / 작성시간: 월, 2013/08/19 - 1:58오전
아래 글 작성자입니다. 전 글의 소스를 통째로 가져와서 가독성이 떨어져 핵심만 뽑았습니다.
callBack()메서드 오버라이드 시키는 방법 없을까요? 신기하게도 되지 않아요.
컴파일은 g++ -o 파일 소스 -lpthread 로 했습니다.
#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;
class Parent
{
public:
virtual void callBack()
{
cout << "Original callBack() reported this: " << this << endl;
}
private:
pthread_t th = 0;
static void *th_func(void *arg)
{
Parent *p = (Parent*)arg;
cout << "*th_func() reported *arg: " << arg << endl;
p->callBack();
}
public:
Parent()
{
if(pthread_create(&th, NULL, th_func, (void*)this) < 0)
cerr << "thread not born." << endl;
else
cout << "thread has born." << endl;
}
~Parent()
{
if(th!=0)
pthread_join(th, NULL);
cout << "joined. Parent leaving." << endl;
}
};
class Child : public Parent
{
public:
void callBack()
{
cout << "child overrided." << endl;
}
Child() : Parent(){}
};
int main()
{
Child *ch = new Child();
delete ch;
return 0;
}Forums:


살짝 손보고 실행해봤는데 오버라이드한 멤버 함수가 잘
살짝 손보고 실행해봤는데 오버라이드한 멤버 함수가 잘 호출됩니다.
쓰레드 관련해서는 클래스 안에 넣는것보다는 외부에서 관리해주시는 것이 더 좋을 것 같습니다.
#include <iostream> #include <unistd.h> #include <pthread.h> class Parent { public: virtual void callBack() { std::cout << "Original callBack() reported this: " << this << std::endl; } static void* th_func(void *arg) { Parent *p = (Parent*)arg; std::cout << "*th_func() reported *arg: " << arg << std::endl; p->callBack(); return 0; } public: Parent() { } virtual ~Parent() { } }; class Child : public Parent { public: virtual ~Child() { } void callBack() { std::cout << "child overrided." << std::endl; } Child() : Parent() { } }; int main() { Parent *ch = new Child(); pthread_t th; if(pthread_create(&th, NULL, &Parent::th_func, ch) < 0) std::cerr << "thread not born." << std::endl; else std::cout << "thread has born." << std::endl; if(th) pthread_join(th, NULL); std::cout << "joined. Parent leaving." << std::endl; delete ch; return 0; }이 문제는 ctor, dtor와 virtual function간의 문제입니다.
처음 코드에서 ch 객체를 delete하기 이전에 sleep(1)로 약간의 delay를 줘 보세요. "child overrided."라는 메세지가 제대로 찍힙니다.
int main() { Child *ch = new Child(); sleep(1); delete ch; return 0; }혹은 Child::~Child() 함수에서 pthread_join을 호출해도 "child overrided."가 뜹니다.
본 현상이 발생하는 원인은 다음과 같습니다.
Parent 클래스의 ctor와 dtor 수행시에는 callBack()이 Parent::callBack()을 가리키게 된다.
Child 클래스의 ctor와 dtor 수행시에는 callBack()이 Child::callBack()을 가리키게 된다.
처음 코드에서 ch 객체를 해제하게 되면 다음과 순서로 작동합니다.
1. Child 클래스 dtor 수행(코드상으로 없으므로 무시)
2. Parent 클래스 dtor 수행(이 경우 callBack은 Parent::callBack()을 가리키게 된다).
3. Parent 클래스 dtor가 수행하고 있을 때 pthread_join이 불리게 되며 th_func의 p->callBack()이 호출될 때에는 Parent::callBack()이 호출되게 된다.
ctor 및 dtor가 호출이 될 때에 VMT(virtual member table)가 바뀌는 시점에 대해 알아 보시기 바랍니다.
자세한 사항은 아래에서 확인해 보세요.
http://www.gilgil.net/10409
http://www.gilgil.net/3311
http://www.gilgil.net/10409
www.gilgil.net
이것저것 테스트해봤습니다.
이것이 클래스 오버라이드라고 하는데요.
http://iopoi3.blog.me/130152756623
이거 그대로 따라해보시는것도 좋을거 같습니다.
그리고. 만드는 구조를 다른 방식으로도. 고민해보셔야 할거 같습니다.
//Dev C++에서 테스트 해봤습니다. //http://iopoi3.blog.me/130152756623 //클래스 오버라이드는 자식을 바꾸기 위한 방식이네요. //http://iopoi3.blog.me/130152756623 //Parent를 사용하고 싶으면. virtual을 빼면 되네요. #include <cstdlib> #include <iostream> #include <process.h> //_beginthreadex using namespace std; class Parent { public: virtual void callBack() { cout << "Original callBack() reported this: " << this << endl; } private: unsigned int id; static unsigned int __stdcall td(void* arg) { Parent *p = (Parent*)arg; cout << "[실행전] *th_func() reported *arg: " << p << " / " << arg << endl; p->callBack(); cout << "[실행후] *th_func() reported *arg: " << p << " / " << arg << endl; } // pthread_t th = 0; static void *th_func(void *arg) { Parent *p = (Parent*)arg; cout << "*th_func() reported *arg: " << arg << endl; p->callBack(); } public: Parent() { // if(pthread_create(&th, NULL, th_func, (void*)this) < 0) // cerr << "thread not born." << endl; // else // cout << "thread has born." << endl; } ~Parent() { // if(th!=0) // pthread_join(th, NULL); // cout << "joined. Parent leaving." << endl; } void setRun(void* p) { cout << "setRun: " << p << " / " << this << endl; _beginthreadex(NULL, 0, td, p, 0, &id); } }; class Child : public Parent { public: void callBack() { cout << endl; cout << "child overrided." << endl; } Child() : Parent() { cout << "Child(): " << this << endl; } }; int main() { //1. 클래스 오버라이드 - 사용 방법. //http://iopoi3.blog.me/130152756623 Child ch; Parent* p = new Parent(); p->setRun(&ch); p = &ch; p->callBack(); //Parent에 virtual이 붙을경우 이런 방식으로 사용하면 안되네요. //2. 사용하신 방법 // Child *ch = new Child(); // delete ch; 이 코드 때문에 죽습니다. 스레드 완료후 실행 되야 할거 같습니다. system("PAUSE"); return EXIT_SUCCESS; } /* //이건 테스팅 방법이 잘못된거 같습니다. //스레드에 인자값으로 Child의 this가 들어가야 합니다. #include <cstdlib> #include <iostream> #include <process.h> //_beginthreadex using namespace std; class Parent { public: virtual void callBack() { cout << "Original callBack() reported this: " << this << endl; } private: unsigned int id; static unsigned int __stdcall td(void* arg) { Parent *p = (Parent*)arg; cout << "[실행전] *th_func() reported *arg: " << p << " / " << arg << endl; p->callBack(); cout << "[실행후] *th_func() reported *arg: " << p << " / " << arg << endl; } // pthread_t th = 0; static void *th_func(void *arg) { Parent *p = (Parent*)arg; cout << "*th_func() reported *arg: " << arg << endl; p->callBack(); } public: Parent() { _beginthreadex(NULL, 0, td, this, 0, &id); // if(pthread_create(&th, NULL, th_func, (void*)this) < 0) // cerr << "thread not born." << endl; // else // cout << "thread has born." << endl; } ~Parent() { // if(th!=0) // pthread_join(th, NULL); // cout << "joined. Parent leaving." << endl; } }; class Child : public Parent { public: void callBack() { cout << endl; cout << "child overrided." << endl; } Child() : Parent(){} }; int main() { //1. 클래스 오버라이드 - 사용 방법. //http://iopoi3.blog.me/130152756623 Parent* p; Child ch; p = &ch; p->callBack(); //Parent에 virtual이 붙을경우 이런 방식으로 사용하면 안되네요. //2. 사용하신 방법 // Child *ch = new Child(); // delete ch; 이 코드 때문에 죽습니다. 스레드 완료후 실행 되야 할거 같습니다. system("PAUSE"); return EXIT_SUCCESS; } 1. 결과. //Parent만 virtual 일 경우. [실행전] *th_func() reported *arg: child overrided. 0x22ff40 / 0x22ff40 child overrided. [실행후] *th_func() reported *arg: 0x22ff40 / 0x22ff40 //둘다 virtual 일 경우. [실행전] *th_func() reported *arg: child overrided. 0x22ff40 / 0x22ff40 child overrided. [실행후] *th_func() reported *arg: 0x22ff40 / 0x22ff40 //Child만 virtual 일 경우. [실행전] *th_func() reported *arg: Original callBack() reported this: 0x22ff44 / 0x22ff44 Original callBack() reported this: 0x22ff440x22ff44 [실행후] *th_func() reported *arg: 0x22ff44 / 0x22ff44 //둘다 virtual이 아닐경우. Original callBack() reported this: [실행전] *th_func() reported *arg: 0x22ff400x 22ff40 / 0x22ff40 Original callBack() reported this: 0x22ff40 [실행후] *th_func() reported *arg: 0x22ff40 / 0x22ff40 2. 결과. Child만 virtual void callBack() 일 경우. [실행전] *th_func() reported *arg: 0x3d2484 / 0x3d2484 Original callBack() reported this: 0x3d2484 [실행후] *th_func() reported *arg: 0x3d2484 / 0x3d2484 둘다 virtual 일 경우. [실행전] *th_func() reported *arg: 0x3d2480 / 0x3d2480 child overrided. [실행후] *th_func() reported *arg: 0x3d2480 / 0x3d2480 Parent만 virtual 일 경우. [실행전] *th_func() reported *arg: 0x3d2480 / 0x3d2480 child overrided. [실행후] *th_func() reported *arg: 0x3d2480 / 0x3d2480 virtual이 없을 경우. [실행전] *th_func() reported *arg: 0x3d2480 / 0x3d2480 Original callBack() reported this: 0x3d2480 [실행후] *th_func() reported *arg: 0x3d2480 / 0x3d2480 #include <cstdlib> #include <iostream> #include <process.h> //_beginthreadex using namespace std; unsigned int __stdcall td(void* arg); class UserSocket { public: void* pmain; void fn_setMain(void* p) { pmain = p; } virtual void onConnection_request(const int fd) // void onConnection_request(const int fd) { printf("UserSocket - onConnection_request(%d)\n", fd); } UserSocket(const char *xProto) { printf("UserSocket\n"); } ~UserSocket() { printf("~UserSocket\n"); } private: unsigned int id; private: static void *listen_thread_func(void *arg) { } public: bool start_listen_thread() { printf("UserSocket - start_listen_thread PREV\n"); _beginthreadex(NULL, 0, td, pmain, 0, &id); printf("UserSocket - start_listen_thread NEXT\n"); return true; } }; class CSocket : public UserSocket { public: void onConnection_request(const int fd) { printf("CSocket - onConnection_request(%d)\n", fd); } public: CSocket() : UserSocket("tcp") { printf("CSocket\n"); } ~CSocket() { printf("~CSocket\n"); } void fn_run() { fn_setMain(this); } }; unsigned int __stdcall td(void* arg) { printf("UserSocket - td PREV\n"); UserSocket* pus = (UserSocket*)arg; if(pus == NULL) { printf("pus is NULL\n"); return 0; } printf("UserSocket - td CENTER\n"); pus->onConnection_request(11); ((CSocket*)pus)->onConnection_request(12); printf("UserSocket - td NEXT\n"); } int main(int argc, char *argv[]) { CSocket s; UserSocket* p = new UserSocket(); p = &s; p->fn_setMain(&s); p->start_listen_thread(); system("PAUSE"); return EXIT_SUCCESS; } class UserSocket이 void onConnection_request(const int fd) 일 경우. UserSocket CSocket --------------------------------- UserSocket - start_listen_thread PREV UserSocket - start_listen_thread NEXT UserSocket - td PREV UserSocket - td CENTER UserSocket - onConnection_request(11) CSocket - onConnection_request(12) UserSocket - td NEXT class UserSocket이 virtual void onConnection_request(const int fd) 일 경우. UserSocket CSocket UserSocket - start_listen_thread PREV UserSocket - start_listen_thread NEXT UserSocket - td PREV UserSocket - td CENTER CSocket - onConnection_request(11) CSocket - onConnection_request(12) UserSocket - td NEXT */----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
댓글 달기