c++의 유형 식별 에 대한 자세 한 설명

9743 단어 c + +유형 식별
1.유형 식별 에 관 한 개념
(1)유형 식별 의 역할
유형 식별 은 대상 을 대상 으로 도입 한 새로운 개념 으로 주로 할당 호환성 원칙 중의 유형 문 제 를 판단 하 는 데 사용 된다.즉,이때 의 데이터 유형 이 기본 유형 인지 파생 유형 인지 판단 하 는 데 사용 된다.
기본 포인터 가 하위 클래스 대상 이나 기본 클래스 가 하위 클래스 대상 이 되 는 별명 을 참조 할 때 유형 식별 을 사용 해 야 합 니 다.

Base *p = new Derived();
Base &r = *p
위의 문장 에 대해 우 리 는 이렇게 인식 할 수 있다.포인터 p 는 Base 형식 이지 만 P 는 새로운 Derived 형식 을 가리 키 기 때문에 포인터 P 의 데이터 형식 을 판단 하기 어렵다.마찬가지 로 인용 r 는 원래 부모 클래스 의 별명 으로 존재 하지만 할당 호환성 으로 인해 인용 r 도 하위 클래스 의 별명 으로 할 수 있 습 니 다.마찬가지 로 이때 인용 r 의 데이터 형식 도 확정 할 수 없습니다.
주:1)이전에 배 운 지식 으로 가상 함수 재 작성 이 없 으 면 컴 파일 러 는 안전 을 위해 포인터 p 를 Base 형식 으로 합 니 다.(컴 파일 기간)
2)가상 함수 재 작성 이 있 으 면 동적 다 중 특성 이 발생 합 니 다.이때 포인터 p 가 가리 키 는 구체 적 인 데이터 형식 에 따라 포인터 p 의 데이터 형식 을 확인 합 니 다.(런 타임
(2)유형 식별의 분류

1)정적 유형:변수(대상)자체 의 유형;컴 파일 단계 에서 사용 하 는 변수의 데이터 형식 을 확인 할 수 있 습 니 다.
2)동적 유형:포인터(참조)가 가리 키 는 대상 의 실제 유형;실행 단계 에서 포인터 가 가리 키 는 구체 적 인 데이터 형식 에 따라 사용 하 는 데이터 형식 을 확인 합 니 다.

Base*b 가 가리 키 는 실제 대상 을 확정 할 수 없습니다.포인터 b 가 하위 대상 을 가리 키 면 프로그램 이 정상적으로 실 행 됩 니 다.포인터 b 가 부모 클래스 대상 을 가리 키 면 프로그램 에 bug 가 나타 날 수 있 습 니 다.
주:g+컴 파일 러 에서 상기 상황 은 모두 정상적으로 운행 할 수 있 지만 후 자 는 사용 하 는 것 을 권장 하지 않 습 니 다.
할당 호 환 원칙 에서 기본 포인터 가 강제로 유형 을 하위 포인터 로 바 꿀 수 있 는 지 여 부 는 동적 유형 에 달 려 있다.(중요 하 다동적 유형 이 하위 대상 이 어야 만 합 법 적 인 전환 을 할 수 있다.
2.동적 유형 을 어떻게 얻 습 니까?
(1)다 형 활용
1)기본 클래스 부터 형식 가상 함 수 를 제공 해 야 합 니 다.
2)모든 파생 류 는 유형 허 함 수 를 다시 써 야 한다.
3)각 파생 클래스 의 유형 ID 는 유일 해 야 합 니 다.
결과:유형 허 함 수 를 호출 하면 현재 의 대상 이 도대체 어떤 유형 인지 알 수 있다.그러면 동적 유형 을 얻 고 동적 유형 식별 효 과 를 얻 을 수 있다.
유형 가상 함 수 를 이용 하여 유형 식별 을 실현 하 다.

 #include <iostream>
 #include <string>
 
 using namespace std;
 
 class Base
 {
 public:
   enum { ID = 0 };
   
   virtual int type() //      
   {
     return ID;
   }
 };
 
 class Derived : public Base
 {
 public:
   enum { ID = 1 };
   
   int type()
   {
     return ID;
   }
   
   void print()
   {
     cout << "I'm a Derived. " << endl;
   }
 };
 
 class Child : public Base
 {
 public:
   enum { ID = 2 };
   
   int type()
   {
     return ID;
   }
 };
 
 void test(Base* pb)
 {
   if( pb->type() == Child::ID )
   {
     Child* pc = static_cast<Child*>(pb);
     //Child* pc = dynamic_cast<Child*>(pb);  //   
     
     cout << "& = " << pc << endl;
     cout << "I'm a Child. " << endl;
   }
   
   if( pb->type() == Derived::ID )
   {
     Derived* pd = static_cast<Derived*>(pb);
     //Derived* pd = dynamic_cast<Derived*>(pb); //   
     
     cout << "& = " << pd << endl;
     pd->print();
   }
   
   if( pb->type() == Base::ID )
   {
     cout << "& = " << pb << endl;
     cout << "I'm a Base. " << endl;
   }
 }
 
 int main(int argc, char *argv[])
 {
   Base b;
   Derived d;
   Child c;
   
   test(&b);
   test(&d);
   test(&c);
   
   return 0;
 }
 /**
 *     :
 * & = 0x7ffccf0dd850
 * I'm a Base. 
 * & = 0x7ffccf0dd860
 * I'm a Derived.
 * & = 0x7ffccf0dd870
 * I'm a Child.
 */
(2)dynamic 이용cast
  1)dynamic_캐 스 트 라 는 키 워드 는 실제 형식 과 지 정 된 형식 이 다 르 면 NULL 로 돌아 갑 니 다.예 를 들 어 하위 클래스 대상 으로 지정 되 었 을 때 부모 포인터 의 동적 유형 이 이 하위 클래스 대상 일 때 전환 에 성 공 했 고 동적 유형 이 부모 클래스 대상 이나 다른 하위 클래스 대상 일 때 전환 에 실 패 했 습 니 다.
  2)dynamic_캐 스 트 가 요구 하 는 대상 유형 은 반드시 다 태 적 이 어야 합 니 다.즉,소재 클래스 에 최소한 하나의 가상 함수 가 있어 야 합 니 다.
3)포인터 와 인용 사이 의 변환 에 만 사용
1.포인터 변환 에 실 패 했 을 때 빈 포인터 로 되 돌려 줍 니 다.
2.인용 변환 시 변환 실패,bad캐 스 트 이상.

 #include <iostream>
 #include <string>
 
 using namespace std;
 
 class Base
 {
 public:
   virtual ~Base()
   {
   
   }
 };
 
 class Derived : public Base
 {
 public:  
   void print()
   {
     cout << "I'm a Derived. " << endl;
   }
 };
 
 class Child : public Base
 {
 
 };
 
 void test(Base* pb)
 {
   // dynamic_cast            ,           
   Derived* pd = dynamic_cast<Derived*>(pb);
   
   if(pd != NULL)
   {
     // Derived    ,       pd  Derived    
     cout << "& = " << pd << endl;
     pd->print();
   }
   else
   {
     Child* pc = dynamic_cast<Child*>(pb);
     
     if(pc != NULL)
     {
       // Child    ,       pc  Child    
       cout << "& = " << pc << endl;
       cout << "I'm a Child. " << endl;
     }
     else
     {
       // Base    ,       pb  Base    
       cout << "& = " << pc << endl; 
       cout << "I'm a Base. " << endl;
     }
   }
 }
 
 int main(int argc, char *argv[])
 {
   Base b;
   Derived d;
   Child c;
   
   test(&b);
   test(&d);
   test(&c);
   
   return 0;
 }
 /**
 *     :
 * & = 0
 * I'm a Base. 
 * & = 0x7ffccf0dd860
 * I'm a Derived.
 * & = 0x7ffccf0dd870
 * I'm a Child.
 */
(3)typeid 활용(이런 방법 추천)
1)typeid 는 하나의 키워드 로 동적 유형 식별 에 사용 된다.
2)typeid 키 워드 는 대응 하 는 매개 변수의 유형 정 보 를 되 돌려 줍 니 다.이 유형 정 보 는 type 입 니 다.info 클래스 대상;
1.매개 변수 가 유형 일 때 정적 형식 정 보 를 되 돌려 줍 니 다.
2.매개 변수 가 변수 일 때:1>매개 변수 내부 에 가상 함수 표 가 존재 하지 않 을 때 정적 유형 정 보 를 되 돌려 줍 니 다.2>매개 변수 변수 내부 에 가상 함수 표 가 존재 할 때 동적 유형 정 보 를 되 돌려 줍 니 다.
3.인자 가 NULL 일 때 이상 을 던 집 니 다.
3)typeid 를 사용 할 때 헤더 파일를 포함해 야 합 니 다.
4)typeid 를 사용 할 때 대상 이나 유형 을 직접 지정 합 니 다.
5)typeid 는 서로 다른 컴 파일 러 내부 에서 이 루어 지 는 것 이 다르다.

int i = 0;

const type_info& tiv = typeid(i); //   i         type_info   ;
const type_info& tii = typeid(int);

cout << (tiv == tii) << endl; // 1
typeid 를 이용 하여 유형 식별 을 실현 하 다

 #include <iostream>
  #include <string>
  #include <typeinfo>
  
  using namespace std;
  
  class Base
  {
  public:
   virtual ~Base()
   {
   }
 };
  
 class Derived : public Base
 {
 public:
   void print()
   {
     cout << "I'm a Derived." << endl;
   }
 };
  
 class Child : public Base 
 {
 public:
   void print()
   {
     cout << "I'm a Child." << endl;
   }
 };
  
 void test(Base* pb)
 {
   const type_info& tb = typeid(*pb);
   
   if( tb == typeid(Derived) )
   {
     Derived* pd = dynamic_cast<Derived*>(pb);
   
     cout << "& = " << pd << endl;
     pd->print();
   }
   else if( tb == typeid(Child) )
   {
     Child* pc = dynamic_cast<Child*>(pb);
     
     cout << "& = " << pc << endl;
     pc->print();
     
   }
   else if( tb == typeid(Base) )
   {
     cout << "& = " << pb << endl;
     cout << "I'm a Base. " << endl;
   }
   
   cout << tb.name() << endl;
 }
  
 int main(int argc, char *argv[])
 {
   Base b;
   Derived d;
   Child c;
   int index;
   char ch;
   
   const type_info& tp = typeid(b);
   const type_info& tc = typeid(d);
   const type_info& tn = typeid(c);
   const type_info& ti = typeid(index);
   const type_info& tch = typeid(ch);
   
   cout<<tp.name()<<endl;
   cout<<tc.name()<<endl;
   cout<<tn.name()<<endl;
   cout<<ti.name()<<endl;
   cout<<tch.name()<<endl;
   
   test(&b);
   test(&d);
   test(&c);
   
   return 0;
 }
 /**
  *     :
  * 4Base
  * 7Derived
  * 5Child
  * i
  * c
  * & = 0x7ffcbd4d6280
  * I'm a Base. 
  * 4Base
  * & = 0x7ffcbd4d6290
  * I'm a Derived.
  * 7Derived
 * & = 0x7ffcbd4d62a0
 * I'm a Child.
 * 5Child
 */ 
결론:
3 가지 동적 유형의 실현 방법 은 세 번 째(typeid)를 선택 하 는 것 을 권장 합 니 다.
다 중 실현 에 대해 다음 과 같은 결함 이 존재 한다.
1)기본 클래스 부터 형식 가상 함 수 를 제공 해 야 합 니 다.
2)모든 파생 류 는 유형 허 함 수 를 다시 써 야 한다.
3)각 파생 류 의 유형 명 은 유일 해 야 한다.
dynamic 에 대하 여cast 구현,유형 변환 결과 만 얻 을 수 있 으 며,진정한 동적 유형 을 얻 을 수 없 으 며,동시에 다이나믹cast 는 다 중 으로 이 루어 져 야 합 니 다.
c++의 유형 인식 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 c+유형 인식 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기