第17课 - 继承与多态(函数重写/虚函数) - 上

第17课 - 继承与多态 - 上_P

    一.函数重写(只发生在父类与子类之间)

        问题:如果子类定义了与父类原型相同的函数会发生什么?

        1.1 函数重写的定义

            1.1.1 在子类中定义与父类中原型相同的函数

            1.1.2 函数重写只发生在父类与子类之间

        

        1.2 函数重写的特点

            1.2.1 父类中被重写的函数依然会继承给子类

            1.2.2 默认情况下子类中重写的函数将隐藏父类中的函数

            1.2.3 通过作用域分辨符::可以访问到父类中被隐藏的函数

       

Source Example 1:
            #include 

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

            class Parent{
                public:
                    void print()
                    {
                        printf("I am Parent!\n");
                    }
            };

            class Child : public Parent
            {
                public:
                    void print()
                    {
                        printf("I am Child!\n");
                    }
            };

            int main(int argc, char** argv) {
                Child child;
                
                /* 输出I am Child! */
                child.print();
                /* 输出I am Parent! */
                child.Parent::print();
                
                return 0;
            }

        1.3 当函数重写遇上了赋值兼容性原则

            

Source Example 1.3:
                #include 

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

                class Parent{
                    public:
                        void print()
                        {
                            printf("I am Parent!\n");
                        }
                };

                class Child : public Parent
                {
                    public:
                        void print()
                        {
                            printf("I am Child!\n");
                        }
                };

                void run()
                {
                    Child child;
                    Parent* pp = &child;
                    Parent& rp = child;
                    
                    /* 输出I am Child! */
                    child.print();
                    /* 输出I am Parent! */
                    pp->print();
                    /* 输出I am Parent! */
                    rp.print();
                }

                int main(int argc, char** argv) {
                    
                    run();
                    
                    return 0;
                }

            问题所在:

                1. C++和C相同,是静态(类型的静态)编译型语言

                2. 在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象

                3. 由于定义了Parent* pp, 所以编译器认为父类指针指向的是父类对象(根据赋值兼容性原则(子类是特殊的父类),这个假设合理)

                4. 由于程序没有允许,所以不可能知道父类指针指向的具体的对象具体是父类还是子类

                5. 从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译结果为调用父类的成员函数

                

                void howToParent(Parent* p)

                {

                    /* 只会输出I am Parent!,因为p是一个Parent*/

                    p->print();

                }

                

                在编译这个函数的时候,编译器不可能知道p指针究竟指向了什么,但是编译器没理由报错。

                于是,编译器认为最安全的做法是编译到父类的print函数,因为父类和子类肯定都有相同的print函数。

                
    

        1.4 函数重写实例

            

#include 

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

            class Boss {
            private:
                static Boss* pInstance;

            public:
                static Boss* GetBossInstance()
                {
                    if (pInstance == NULL)
                    {
                        pInstance = new Boss;
                    }
                    
                    return pInstance;
                }
                
                int Kill()
                {
                    return 10;
                }
                
                ~Boss()
                {
                    pInstance = NULL;
                }
                    return 8;
                }
            };

            class newMaster : public Master{
            public:
                int EnghtSword()
                {
                    return Master :: EnghtSword() * 2;
                }
            };

            void filedPK(Boss* boss, Master* master)
            {        
                                    /* 无论传入的是Master还是newMaster,都只会调用Master里面的EnghtSword()函数 */
                if (boss->Kill() > master->EnghtSword())
                {
                    printf("master is killed!\n");
                }
                else
                {
                    printf("boss is killed!\n");
                }
            }

            int main(int argc, char** argv) {
                
                Boss* boss = Boss :: GetBossInstance();
                Master master;
                newMaster newm;
                
                printf("Boss PK Master\n");
                
                filedPK(boss, &master);
                
                printf("\n");
                
                printf("Boss PK newMaster\n");
                
                filedPK(boss, &newm);
                
                return 0;
            }

            最终输出结果如下:
                第17课 - 继承与多态(函数重写/虚函数) - 上_第1张图片
                

    二.多态的本质

        2.1 面向对象的新需求

            2.1.1 根据实际对象类型来判断重写函数的调用

            2.1.2 如果是父类指针指向的是父类对象,则调用父类中定义的函数

            2.1.3 如果是父类指针指向的是子类对象,则调用子类中定义的重写函数

            

        2.2 面向对象中的多态

            根据实际的对象类型决定函数调用语句的具体调用目标

            多态:同样的调用语句有多种不同的表现形态

    

        2.3 C++中的多态支持

            2.3.1 C++中通过virtual关键字对多态进行支持

            2.3.2 使用virtual声明的函数被重写后即可展现多态特性

                被virtual声明的函数就是虚函数

                
        

Source Example 2:
            #include 

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

            class Boss {
            private:
                static Boss* pInstance;

            public:
                static Boss* GetBossInstance()
                {
                    if (pInstance == NULL)
                    {
                        pInstance = new Boss;
                    }
                    
                    return pInstance;
                }
                
                int Kill()
                {
                    printf("Boss Kill()!\n");
                    return 10;
                }
                
                ~Boss()
                {
                    pInstance = NULL;
                }
                        
            };

            Boss* Boss :: pInstance = NULL;

            class Master {
            public:
                /* 虚函数,在父类里面声明 */
                virtual int EnghtSword()
                {
                    printf("Master EnghtSword()!\n");
                    return 8;
                }
            };

            class newMaster : public Master{
            public:
                /* 最规范的写法要在子类里面加上virtual关键字 */
                virtual int EnghtSword()
                {
                    printf("newMaster EnghtSword()!\n");
                    return Master :: EnghtSword() * 2;
                }
            };

            void filedPK(Boss* boss, Master* master)
            {
                if (boss->Kill() > master->EnghtSword())
                {
                    printf("master is killed!\n");
                }
                else
                {
                    printf("boss is killed!\n");
                }
            }

            int main(int argc, char** argv) {
                
                Boss* boss = Boss :: GetBossInstance();
                Master master;
                newMaster newm;
                
                printf("Boss PK Master\n");
                
                filedPK(boss, &master);
                
                printf("\n");
                
                printf("Boss PK newMaster\n");
                
                filedPK(boss, &newm);
                
                return 0;
            }

    三.小结

        3.1 函数重写是面向对象中很可能发生的情形

        3.2 函数重写只可能发生在父类与子类之间

        3.3 需要根据实际对象的类型确定调用的具体函数

        3.4 virtual关键字是C++中支持多态的唯一方式

        3.5 被重写的虚函数即可表现为多态的特性

        
        
        
       
 

你可能感兴趣的:(C++学习笔记,C++,函数重写,多态)