C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[1134] 가상메소드 버추얼테이블 바꿔치기 하기
김태선 [cppbuilder] 28455 읽음    2013-06-14 12:21
가상 함수는 클래스에서 다형성을 구현하는 방법입니다.
이는 실지로는 가상 함수 테이블(Virtual Table)을 통해 구현되기 때문에
이 특성을 이용해서 본래 구현된 가상 함수나 메소드가 아닌 다른 함수나 메소드가 실행되게 할 수 있습니다.

이런 경우 코드를 보는게 훨씬 빠르기 때문에 아래 코드를 보시면
Test 클래스를 상속 받아 TTest 클래스가 존재하고
add 라는 가상 함수가 오버라이딩되어 있습니다.
add 함수는 주어진 정수 값이 일정한 값을 더해서 리턴하는 간단한 테스트용 함수입니다.

그래서 Test::add(10) 을 호출하면 11이 리턴.
TTest::add(10) 을 호출하면 12가 리턴 됩니다.
그런데, add함수를 전혀 다른 클래스의 내가 원하는 함수(이 함수는 가상함수이던 아니던 관계 없습니다)로
바꿔치기하는 예제입니다.


//--------------------------------------------------------------------------- 
void __fastcall TFormMain::FormCreate(TObject *Sender) 
{ 
    class Test 
    { 
    public: 
        int v; 
        virtual int add(int a) 
        { 
            return a + 1; 
        } 
    }; 

    class TTest : public Test 
    { 
    public: 
        virtual int add(int a) 
        { 
            return a + 2; 
        } 
    }; 


    TTest aa; 
    //aa.v = 100; 
    int n = aa.add(10); 
    Caption = n;   // 확인: 12가 리턴됨.
    Test *bb = &aa; 

    typedef int (__closure *TFunc2)(int); 
    TFunc2 func = &_addtest; 
    asm 
    { 
        lea eax, [bb] 
        mov eax, [eax] 
        lea edx, [func] 
        mov [eax], edx 
    }; 
    n = bb->add(10);   
    Caption = n;  // 확인:  n 값은 15가 리턴됨. 
} 

// 이 메소드로 바꿔치기 할 것입니다.

int    TFormMain::_addtest(int a) 
{ 
    return a + 5; 
} 
//--------------------------------------------------------------------------- 


이 코드에 보시면 버추얼 메소드 TTest :: add 를
다른 클래스의 메소드 _addtest로 바꿔치기한 것입니다.
그래서 bb->add(10)을 호출하면
TFormMain 클래스의 바꿔치기한 메소드가 실행되어 15를 리턴합니다.


심심할 때 보는 팁이었습니다.


팁 속에 팁이라고나 할까요.
위 코드를 보시면 어떻게 클래스 함수 포인트를 조작하는지 알수 있습니다.

이렇게 조작이 가능한 이유는,
VirtualTable 자체가 _DATA 영역에 놓여 있어 수정이 가능하기 때문입니다.
VirtualTable을 가르키는 클래스 인스턴스의 선두에 놓이는 VirtualTable Pointer는
위 예제의 경우는 인스턴스를 스택에 생성했으므로 스택에 놓이는 거고,
만일 전역 변수이면 _DATA 정적 데이타 영역에 놓이고
new로 생성하면 힙에 놓이게 됩니다.


+ -

관련 글 리스트
1134 가상메소드 버추얼테이블 바꿔치기 하기 김태선 28455 2013/06/14
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.