第27课 - 动态类型识别

第27课 - 动态类型识别

    一.动态类型

        1.1 由于基类指针可以直接指向派生类对象,因此可能存在指针所指类型与具体指向对象类型不同的情况

            Parent* p = new Child();

        1.2 动态类型指的是基类指针所指向对象的实际类型

          void test(Parent* p)
            {
                /* 当p的动态类型为Child时,转换成功 */
                /* 否则,可能出现无法预知的错误 */
                Child* c = (Child*)p;
            }
           

            基类指针是否可以强制类型转换为子类指针取决于动态类型!

    问题: 如何得到一个指针的动态类型??

        

    二.动态类型识别的方法

        2.1 C++中的多态根据实际对象类型调用对应的虚函数

            2.1.1 可以在基类中定义虚函数返回具体的类型信息
            2.1.2 所有的派生类都必须实现类型相关的虚函数
            2.1.3 每个类中的类型虚函数都需要不同的实现
      
  Source Example 2.1:
            #include <iostream>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */
            using namespace std;

            class Parent {
            public:
                enum {
                    ID = 0
                };
                
                virtual int GetType()
                {
                    return ID;
                }
            };

            class Child : public Parent {
            public:
                enum {
                    ID = 1
                };
                
                virtual int GetType()
                {
                    return ID;
                }

                int Add (int a, int b)
                {
                    return a + b;
                }
            };

            void test (Parent *p)
            {
                if (p->GetType() == Child :: ID)
                {
                    Child* c = (Child*)p;
                    cout<<c->Add(2,3)<<endl;
                }
                
                if (p->GetType() == Parent :: ID)
                {
                    cout<<"Parent Type"<<endl;
                }
            }

            int main(int argc, char** argv) {
                Child c;
                Parent p;
                
                test(&c);
                test(&p);
                
                return 0;
            } 

            输出结果如下:


                
            2.1.4 使用虚函数进行动态类型识别的缺陷
                a.必须从基类开始提供类型虚函数
                b.所有的派生类都必须重写类型虚函数
                c.每个派生类的ID都必须唯一
                

                利用虚函数进行动态类型识别的方法可以满足工程的需要,但是维护性会随着派生类的增多而成指数型增加。

                解决方案:    将ID替换为类的名称

              
  Source Example 2.1.4:

                    #include <iostream>
                    #include <string.h>

                    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
                    using namespace std;

                    class Parent {
                    public:

                        virtual const char * GetType()
                        {
                            return "Parent";
                        }
                    };

                    class Child : public Parent {
                    public:
                        
                        virtual const char * GetType()
                        {
                            return "Child";
                        }

                        int Add (int a, int b)
                        {
                            return a + b;
                        }
                    };

                    void test (Parent *p)
                    {
                        if (strcmp (p->GetType(), "Child") == 0)
                        {
                            Child* c = (Child*)p;
                            cout<<c->Add(2,3)<<endl;
                        }
                        
                        if (strcmp (p->GetType(), "Parent") == 0)
                        {
                            cout<<"Parent Type"<<endl;
                        }
                    }

                    int main(int argc, char** argv) {
                        Child c;
                        Parent p;
                        
                        test(&c);
                        test(&p);
                        
                        return 0;
                    }

                方案缺点: 进行字符串的比较,程序效率会降低很多!

                

    三.新的关键字dynamic_cast

        3.1 dynamic_cast 是C++中新型转换关键字

        3.2 dynamic_cast 主要用于基类和派生类之间的转换

        3.3 dynamic_cast要求使用目标对象类型是多态的

            3.3.1 即:所在类族至少有一个虚函数(在工程中一般将析构函数定义为析构函数)
            3.3.2 用于指针转换时,转换失败返回空指针
            3.3.3 用于引用转换时,转换失败将引发bad_cast异常
            
    
Source Example 3:
        #include <iostream>
        #include <string.h>

        /* run this program using the console pauser or add your own getch, system("pause") or input loop */
        using namespace std;

        class Parent {
        public:
            /* 必须存在一个虚函数,在工程中一般将析构函数定义为析构函数 */
            virtual ~Parent()
            {
            }
        };

        class Child : public Parent {
        public:
            int Add (int a, int b)
            {
                return a + b;
            }
        };

        void test (Parent *p)
        {
            Child* c = dynamic_cast<Child*>(p);
            
            if (c != NULL)
            {
                cout<<"Dynamic Type:"<<"Child"<<endl;
                cout<<"add:"<<c->Add(2,3)<<endl;
            }
            else
            {
                cout<<"Dynamic Type:"<<"Parent"<<endl;
            }
        }

        int main(int argc, char** argv) {
            Child c;
            Parent p;
            
            test(&c);
            test(&p);
            
            return 0;
        }
        输出结果如下:    
        

            3.4 dynamic_cast 的优势

                3.4.1 不用显示的声明和定义类型虚函数
                3.4.2 不用为类族中的每个类分配ID
            

            3.5 dynamic_cast 的缺陷

                3.5.1 只能用于具有虚函数的类族
                    

                    使用dynamic_cast进行动态识别可以取代类型虚函数的方案,但是在本质上dynamic还是需要类族中存在虚函数.

               (在工程上常把析构函数作为这个虚函数定义)

                    

    四.C++提供了typeid关键字用于动态获取类型信息

        4.1 typeid 关键字返回对应参数的类型信息

        4.2 typeid 返回一个type_info类对象

            4.2.1 当typeid的参数为NULL时,抛出bad_typeid异常

        4.3 type_info类的使用需要包含<typeinfo>

        
        
Source Example 4(typeid关键字的使用):
            #include <iostream>
            #include <string.h>
            #include <typeinfo>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */
            using namespace std;

            class Parent {
            public:
                virtual ~Parent()
                {
                }
            };

            class Child : public Parent {
            public:
                int Add (int a, int b)
                {
                    return a + b;
                }
            };

            void test(Parent *p)
            {                         /* typeid的参数可以是具体的对象,也可以是类型 */
                if ( typeid (*p) == typeid(Child))
                {
                    Child *c = dynamic_cast<Child*>(p);
                    cout<<"Dynamic Type:"<<"Child"<<endl;
                    cout<<"add:"<<c->Add(2,3)<<endl;
                }
                else
                {
                    cout<<"Dynamic Type:"<<"Parent"<<endl;
                }
            }

            int main(int argc, char** argv) {
                int index;
                char ch;
                Child c;
                Parent p;
                
                const type_info& tp = typeid(Parent);
                const type_info& ti = typeid(index);
                const type_info& tc = typeid(Child);
                const type_info& tch = typeid(ch);
                
                /* 输出6Parent,这个类型名字是在GCC内部系统里面的 */
                /* 注意,不要用这个名字来些代码,例如strcmp(tp.name(), "Parent") == 0 */
                cout<<tp.name()<<endl;
                /* 输出i */
                cout<<ti.name()<<endl;
                /* 输出5Child */
                cout<<tc.name()<<endl;
                /* 输出c */
                cout<<tch.name()<<endl;
                
                test(&p);
                test(&c);
                
                return 0;
            }
        输出结果如下:    
        
    

    五.小结

        5.1 C++中可以通过多态的方式进行动态类型识别

        5.2 dynamic_cast关键字可用于动态类型识别(只能用于类的对象)

        5.3 typeid关键字在C++中专用于动态类型识别(可以用于任意类型)

            

    
            
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值