MFC 독서노트 탐색 - RTTI

8199 단어
RTTI(Runtime Type Identification): 런타임 유형 식별을 통해 프로그램이 실행될 때 객체가 범주에 속하는지 알 수 있습니다.
 
1. RTTI를 사용하려면 세 가지를 주의해야 한다.
1. 컴파일할 때/GR 옵션을 선택해야 한다(/GR은 enable C++ RTTI를 의미한다)
2. typeinfo를 포함한다.h
3. 새로운 typeid 연산자.typeid의 매개 변수는 형식 별명일 수도 있고 대상 바늘일 수도 있습니다.그것은 typeinf & 로 전송됩니다.
type_info는 typeinfo에 정의된 클래스입니다.h중:
<span style="font-size:14px;">class type_info
{
public:
     virtual ~type_info();
     int operator==(const type_info& rhs) const;
     int operator!=(const type_info& rhs) const;
     int before(const typ_info& rhs) const;
     const char* name() const;
     const char* raw_name() const;
private:
     ...
};</span>

2. RTTI의 실현 원리
만약 당신이 제품이 하나 있다면, 당신이 제품의 모델을 얻고 싶다면, 당신은 모델 대조표를 찾아야 합니다.같은 이치로 운행할 때 어떤 종류의 모델을 알고 싶다면, 클래스에 추가 정보를 추가하여 클래스의 유형 정보를 기록해야 한다.
1. MFC의 모든 클래스에는 CRuntimeClass 구성원 변수가 있어 이 추가 기록 구조를 충당한다.
RTTI와 관련된 CruntimeClass 객체:
<span style="font-size:14px;">struct CRuntimeClass
{
      LPCSTR m_lpszClassName;
      int m_nObjectSize;
      UINT m_wSchema;
      CObject* (PASCAL* m_pfnCreateObject)();
      CRuntimeClass* m_pBaseClass;
      static CRuntimeClass* pFirstClass;
      CRuntimeClass* m_pNxtClass;
      CObject* CreateObject();
}</span>

     2、DECLARE_DYNAMIC/IMPLEMENT_DYNAMI
(1) CRuntimeClass 대상을 클래스에 끼워넣고 이 대상의 주소를 잡을 수 있는 함수를 설명하기 위해 MFC는DECLARE 를 정의했다DYNAMIC 매크로: #define DECLAREDYNAMIC(class_name) \
public:\
        static CRuntimeClass class##class_name;\
        virtual CRuntimeClass* GetRuntimeClass() const;
참고: 매크로의 ##은 컴파일러가 좌우 문자열을 함께 연결하는 것을 알려줍니다.
예: DECLAREDYNAMIC(CView)
컴파일러 선행 프로세서가 컴파일한 코드는 다음과 같습니다.
 public:
          static CRuntimeClass classCView;
          virtual CRuntimeClass* GetRuntimeClass() const;
(2), 클래스 레코드(각 CRunTimeClass 대상)의 내용을 지정하고 직렬 작업을 클래스에 삽입하기 위해 MFC는 IMPLEMENT 를 정의했다.DYNAMIC 매크로:
#define IMPLEMENT_DYNAMIC(class_name, base_class_name)\
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
 
_IMPLEMENT_RUNTIMECLASS는 또 하나의 매크로입니다.
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew)\
      static char _lpsz##class_name[] = #class_name;\
      CRuntimeClass class_name::class##class_name = {\
              _lpsz##class_name, sizeof(class_name), wSchema, pfnNew\
                       RUNTIME_CLASS(base_class_name),  NULL };\
      static AFX_CLASSINIT  _init_##class_name(&class_name::class##class_name);\
      CRuntimeClass* class_name::GetRuntimeClass()  const  \
               {   return &class_name::class##class_name;}\
예: RUNTIMECLASS(class name) 매크로는 다음과 같이 정의됩니다.
      #define RUNTIE_CLASS(class_name)\
             (&class_name::class##class_name)
 
여기서: AFXCLASSINIT은 다음과 같은 구조 함수를 포함하는 구조체입니다.
         struct AFX_CLASSINIT
         {
                 AFX_CLASSINIT(CRuntimeClass* pNewClass);
         }
구조 함수는 다음과 같이 정의됩니다.
        AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClss* pNewClass)
        {
                pNewClass ->m_pNextClass = CRuntimeClass::pFirstClass;
                CRuntimeClass::pFirstClass = pNewClass;
        }
이 구조 함수는 분류 정보의 직렬을 담당하는 것이 분명하다.
인스턴스:
     //in header file
      class CView  : public CWnd
      {
             DECLARE_DYNAMIC(CView)
             ...
      };
      //in implementation file
      IMPLEMENT_DYNAMIC(CView, CWnd)
위의 코드 매크로가 확장된 경우:
     //in header file
      class CView : public CWnd
      {
       public :
                  static CRuntimeClass classCView;
                  virtual CRuntimeCLass* GetRuntimeClass() const;
                  ...  
      }
     //in implementation file
     static char _lpszCView[] = "CView";
     CRuntimeClass CView::classCView = {
            _lpszCView, sizeof(CView), 0xFFFF, NULL, &CWnd::classCWnd, NULL);
     static AFX_CLASSINIT _init_CView(&CView::classCView);
     CRuntimeClass* CView::GetRuntimeClass() const
             {return &CView::classCView; }
 
(3) 직렬의 머리는 특수 처리를 해야 하기 때문에 루트 클래스 CObject에서 기존의 매크로 DECLARE 를 적용할 수 없습니다.DYNAMIC 및
IMPLEMENT_DYNAMIC, 다음과 같이 특별히 설계해야 합니다.
// in header file
class CObject
{
public:
   virtual CRuntimeClass* GetRuntimeClass() const;
...
public:
   static CRuntimeClass classCObject;
};
// in implementation file
static char szCObject[] = "CObject";
struct CRuntimeClass CObject::classCObject=
{    szCObject, sizeof(CObject), 0xffff, NULL, NULL };
   static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
   CRuntimeClass* CObject::GetRuntimeClass() const
   {
      return &CObject::classCObject;
   }
// in implementation file
CRuntimeClass* CRuntimeClass::pFirstClass= NULL;

 
(4), AFX 정보CLASSINIT 구조체
RTTI宏의 실현에 관해서는 사실상 이해할 필요가 없다. 사용할 줄만 알고 어떻게 된 일인지 알면 된다.그러나 일부 디자인 사상, 디자인 방법은 참고할 수 있다.
      AFX_CLASSINIT 구조체는 데이터 구성원이 없고 하나의 매개 변수를 가진 구조 함수만 있으며 사용할 때 전역 변수만 정의할 뿐 후속 코드에서 사용하지 않는다. 그 가치는 구조기에 있다. 왜냐하면 구조기에서 분류 직렬을 실현했기 때문이다.우리는 실제 수요가'직접'을 하는 것을 발견했지만 해결 방법은'한 변수를 정의하는 것'이다. 그 전에 나는 이런 상황을 만난 적이 없다. 전체 함수를 쓰면 되지 않겠는가?왜 이러는 거야?나는 이렇게 하는 것이 C++의 봉인성을 고려한 것이라고 생각한다.
(5) RTTI는 직접도이자 상속도이다
'직렬 연결' 은 원본 파일의 모든 성명과 실현된 클래스를 하나의 체인 테이블로 연결하는 것을 의미하며, 직렬 연결 순서는 헤더 파일의 클래스 정의 순서입니다.(그래서 전체적으로 기류가 앞에 있고 파생류가 뒤에 있으며 같은 부류에서 계승된 자류의 직렬 순서는 먼저 정의된 선직렬 순서이다).
'계승도'는 표지류의 계승 차원임에 틀림없다.
RTTI에는 클래스의 직렬 연결 순서와 클래스의 계승 단계를 표시하고 CRuntimeClass 구조체에서 구성원인 CRuntimeClass*mpBaseclass는 직렬 클래스 계승 차원 역할을 하고 구성원 CRuntimeClass*mpNextClass 시작 클래스의 연결 순서입니다.
 
      3、DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE
동적 생성: 프로그램이 실행되는 동안 동적으로 얻어진 분류(일반적으로 파일을 읽는 것)에 따라 프로그램에 대상을 만들어야 한다.
상술한 유형 식별이 있으면 동적 생성 기술은 간단하다. 입력의 유형에 따라 유형형 녹음망에서 대응하는 요소를 찾은 다음에 기록의 구조 함수를 호출하여 대상을 만든다.
참고: CRuntimeClass의 함수 포인터 mpfnCreateObject 및 구성원 메서드CreateObject().
(1)、DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE의 내용
      #define DECLARE_DYNCREATE(class_name)\      DECLARE_DYNAMIC(class_name)\      static CObject* PASCAL CreateObject();
      #define IMPLEMENT_DYNCREATE(class_name, base_class_name)\     CObject* PASCAL class_name::CreateObject()\     { return new class_name; }\     _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF,\     class_name::CreateObject)
표시, 1*, DECLAREDYNCREATE 및 IMPLEMENTDYNCREATE 매크로에 DECLARE 포함DYNAMIC 및 IMPLEMENTDYNAMIC 매크로.
2*,CreateObject 내부는 사실상 new의 대상입니다. 동적으로 만들어진 대상은 사용이 끝난 후에 수동으로 delete 삭제를 호출해야 합니다.
3*, MFC 응용 프로그램에서 CWnd, CFrameWnd, CXXXWnd, CXXXFrameWnd, CXXXDoc, CXXXView는 모두 DECLARE 를 사용합니다.DYNCREATE 및 IMPLEMENTDYNCREATE 매크로, 나머지는 DECLAREDYNAMIC 및 IMPLEMENTDYNAMIC 매크로.
 
3. RTTI의 사용
(1), 유형 인식, IsKindOf()
CObject에 IsKindof 구성원 방법을 추가하면 매개 변수가 지정한 CRuntimeClass 대상과 형별록의 요소를 일일이 비교할 수 있습니다. 비교는 성공적으로true를 되돌려주고 실패는false를 되돌려줍니다.
<span style="font-size:14px;">BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
	CRuntimeClass* pClassThis = GetRuntimeClass();
	while(pClassThis != NULL)
	{
		if(pClassThis == pClass)
			return TRUE;
		pClassThis = pClassThis->m_pBaseClass;
	}
	return FALSE;
}</span>

주의: IsKindof에서 추적하는 것은 mpBaseClass.따라서 하나의 종류가 어떤 기본 유형인지 아닌지를 판단할 수 있다.
예: CView* pView = new CView;
            pView ->IsKindOf(RUNTIME_CLASS(CWinApp));//여기에 입력한 매개 변수는 CWinApp 클래스의 정적 구성원인 classcWinApp의 주소입니다.
함수 IsKind Of의 실행 과정은 CView, CWnd, CCmdTarget, CObject의 라인 경로에 따라 CruntimeClass 대상 지침을 얻을 때마다'&CView::classcView'지침과 비교합니다.맨 위에 있는 CRuntimeClass 객체의 m 까지pBaseClass 구성원은 NULL입니다.결과를 반환합니다.
(2), 동적 생성 대상
CView 객체를 동적으로 생성합니다.
             CObject* pObject = RUNTIME_CLASS(CView)->CreateObject();
객체를 삭제하려면 다음과 같이 하십시오.
           if(pObject) {delete pObject; pObject = NULL;}
 

좋은 웹페이지 즐겨찾기