zoukankan      html  css  js  c++  java
  • 嘀嘀咕(5)

    1.多态

    由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应。
    

    多态成立的条件

    1 要有继承
    2 要有虚函数重写
    3 要有父类指针(父类引用)指向子类对象
    
    //英雄类
    class Hero
    {
    public:
        virtual int getAd() {
            return 10;
        }
    };
    
    
    class AdvHero :public Hero
    {
    public:
        virtual int getAd()
        {
            return 1001;
        }
    };
    
    //怪兽类
    class Monster
    {
    public:
        int getAd() {
            return 1000;
        }
    };
    
    
    //战斗方法
    void playerFight(Hero *hp, Monster *mp)
    {
        //多态对于编译器来讲的,也是一个动态联编,也是一个迟邦定。
        if (hp->getAd() > mp->getAd()) { //hp->getAd 发生了多态
            cout << "英雄胜利, 怪兽被打死" << endl;
        }
        else {
            cout << "英雄挂了,怪兽赢了" << endl;
        }
    }
    
    Hero h;
    
    Monster m;
    playerFight(&h, &m);
    
    
    AdvHero advH;
    playerFight(&advH, &m);
    

    原理

    当类中声明虚函数时,编译器会在类中生成一个虚函数表;
    当存在虚函数时,每个对象中都有一个指向虚函数表的指针(vptr指针)
    
    class Parent
    {
    public:
         Parent(int a) {
               this->a = a;
         }
         virtual void func(int a)
         {
               cout << "Parent::func(int)..." << endl;
         }
         void func(int a, int b, int c)        //不是虚函数
         {
               cout << "Parent::func(int ,int ,int )...." << endl;
         }
    private:
         int a;
    };
    
    class Child :public Parent
    {
    public:
         Child(int a, int b) :Parent(a)
         {
               this->b = b;
         }
         virtual void func(int a)               
         {
               cout << "Child: func(int)..." << endl;
         }
         void func(int a, int b) {
               cout << "Child :func(int ,int )..." << endl;
         }
         virtual void func(int a, int b, int c)
         {
               cout << "Child ::func(int ,int ,int )..." << endl;
         }
    private:
         int b;
    };
    
    void myFunc(Parent *pp)
    {
         pp->func(10);                      //结果图1
        //pp->func(10,20,30);            //结果图2
    }
    
    
    Parent pp(10);
    Child pc(100,200);
    myFunc(&pp);    //Parent *pp = &pp;   pp->func(10);   查找func是否为虚函数,若为虚函数,调用对象的vptr指针所指向的虚函数表中的函数(动态链编);若不为虚函数,直接确定被调用函数(静态链编)
    myFunc(&pc);
    

    图1:

    图2:

    多态用于虚析构函数

    虚析构函数用于指引  delete  运算符正确析构动态对象  
    
    class  A
    {
    public:
        A()
        {
            p  =  new  char[20];
            strcpy(p,  "obja");
            printf("A()
    ");
        }
        virtual  ~A()
        {
            delete  []  p;
            printf("~A()
    ");
        }
    private:
        char  *p;
    };
    
    class  B  :  public  A
    {
    public:
        B()
        {
            p  =  new  char[20];
            strcpy(p,  "objb");
            printf("B()
    ");
        }
        ~B()
        {
            delete  []  p;
            printf("~B()
    ");
        }
    private:
        char  *p;
    };
    
    class  C  :  public  B
    {
        public:
            C()
            {
                p  =  new  char[20];
                strcpy(p,  "objc");
                printf("C()
    ");
            }
            ~C()
            {
                delete  []  p;
                printf("~C()
    ");
            }
        private:
            char  *p;
    };
    
    //通过⽗父类指针把所有的⼦子类对象的析构函数都执⾏行⼀一遍
    //通过⽗父类指针释放所有的⼦子类资源  
    void  howtodelete(A  *base)
    {
        delete  base;
    }
    
    int  main()
    {
        C  *myC  =  new  C;
        //delete  myC;  //直接通过⼦子类对象释放资源  不需要写virtual  
        howtodelete(myC);//通过⽗父类的指针调⽤用释放⼦子类的资源
        return  0;
    }
    

    VPTR指针分步初始化

    class Parent
    {
    public:
        Parent(int a)
        {
            cout << "Parent(int ..)" << endl;
            this->a = a;
    
            print();//是调用父类的print()
                   
        }
    
        virtual void print()
        {
            cout << "Parent::print()...a = "<<a << endl;
        }
    private:
        int a;
    };
    
    class Child :public Parent
    {
    public:
        Child(int a, int b) :Parent(a) //在调用父类的构造器的时候,会将vptr指针当做父类来处理。
                                                    //此时会临时指向父类的虚函数表
        {
            cout << "Child (int ,int )" << endl;
            this->b = b;
            print();//此时vptr指针已经回到了 子类的表, 调用的是子类的print函数。
    
        }
    
        virtual void print() {
            cout << "Child ::Print()..b = " << b << endl;
        }
    private:
        int b;
    };
    

    c模拟多态:函数指针做函数参数

    int  add(int  a,  int  b)
    {
        return  a  +  b;
    }
    
    int sub(int a, int b)
    {
        return a-b;
    }
    
    int  libfun(int  (*pDis)(int  a,  int  b), int a, int b)
    {
    
        //add(1,3);   //直接调⽤用add函数
        printf("%d",  pDis(a,  b));  //通过函数指针做函数参数,间接调⽤用add函数
        return  0;
    }
    
    int  main(void)
    {
        int  (*pfun)(int  a,  int  b);//定义⼀一个函数指针pfun  指向  int  ()(int,  int)函数类型
        pfun  =  add;
        //pfun = sub;
        libfun(pfun,3,4);
        return  0;
    }
    

    2.重载、重写、重定义

    重载:发生在同一个作用域下
    重写:父子类中,虚函数被子类重写
    重定义:
    a 如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无
    virtual,基类的函数被隐藏。
    b 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没
    有vitual关键字,此时,基类的函数被隐藏。
    
  • 相关阅读:
    ASP.NET 2.0 web.config数据库连接设置与读取
    一句话影评
    百度地图api示例
    centos5.8 误改/etc/fstab后导致系统进不去 解决办法
    Nginx Gzip 压缩配置
    数据库设计的三大范式
    CentOS 6.0下vncserver安装配置
    MySQL配置文件my.cnf设置
    Linux下zip加密压缩
    keepalived的log
  • 原文地址:https://www.cnblogs.com/EngineerZhang/p/9925408.html
Copyright © 2011-2022 走看看