详解c++中的类型识别

2020-06-30 11:00:33丽君

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.
 */