11_c++多态

c++多态

参考文章:https://www.cnblogs.com/dormant/p/5223215.html

1、什么是多态

基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。即对象类型是派生类,就调用派生类的函数;对象类型是基类,就调用基类的函数。

class Human{
private:
    int a;
public:
    virtual void eating(void){ cout<<"use hand to eat"<<endl; }/* 基类实现虚函数 */
};

class Englishman : public Human {
public:
    void eating(void) { cout<<"use knife to eat"<<endl; }//派生类重写该函数
};


class Chinese : public Human {
public:
    void eating(void) { cout<<"use chopsticks to eat"<<endl; }//派生类重写该函数
};

void test_eating(Human& h)//多态只发生在引用和指针中,值传递则不行。
{
    h.eating();//根据对象的实际类型调用不同的eating函数
}

int main(int argc, char **argv)
{
    Human h;
    Englishman e;
    Chinese c;

    test_eating(h);
    test_eating(e);
    test_eating(c);

    return 0;
}

2、为什么需要多态?

网上的例子:将父类比喻为电脑的外设接口,子类比喻为外设,现在我有移动硬盘、U盘以及MP3,它们3个都是可以作为存储但是也各不相同。如果我在写驱动的时候,我用父类表示外设接口,然后在子类中重写父类那个读取设备的虚函数,那这样电脑的外设接口只需要一个。但如果我不是这样做,而是用每个子类表示一个外设接口,那么我的电脑就必须有3个接口分别来读取移动硬盘、U盘以及MP3。若以后我还有SD卡读卡器,那我岂不是要将电脑拆了,焊个SD卡读卡器的接口上去?

一个接口,多种实现面向接口编程,大家都遵循这个接口。

3、多态的本质

存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。 通过虚表指针就可以调用到类对象自身的函数。
class Human{
private:
int a;
public:
virtual void eating(void){ cout<<”use hand to eat”<

4、多态的注意事项

a、析构函数一般都声明为虚构函数。
如下例子,如果析构函数不声明为虚函数,那么对象在被销毁的时候将会出错。

class Human{
private:
    int a;
public:
    virtual void eating(void){ cout<<"use hand to eat"<<endl; }
    virtual ~Human() { cout<<"~Human()"<<endl; }
};

class Englishman : public Human{
public:
    void eating(void){cout<<"use knife to eat"<<endl;}
    virtual ~Englishman(){cout<<"~Englishman()"<<endl;}
};

class Chinese : public Human {
public:
    void eating(void) { cout<<"use chopsticks to eat"<<endl; }
    virtual ~Chinese() { cout<<"~Chinese()"<<endl; }
};

void test_eating(Human h)
{
    h.eating();
}

int main(int argc, char **argv)
{
    Human * h = new Human;
    Englishman *e = new Englishman;
    Chinese *c = new Chinese;
    Human *p[3] = {h, e, c};
    int i;
    for(i = 0; i < 3; i++)
    {
        p[i]->eating();
      /* 如果析构函数不声明为析构函数,
       * 这里销毁对象时,将会调用3次Human
       * 的析构函数,这显然是不对的。
       */
        delete p[i];
    }
    return 0;
}

b、如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的。 但是有一种情况返回值可以不同,就是返回类的指针。即返回不同类的指针的同名、同参数的函数可以实现多态

class Human{
private:
    int a;
public:
    virtual void eating(void){cout<<"use hand to eat"<<endl;}
    virtual ~Human() { cout<<"~Human()"<<endl; }
    virtual Human* test(void)   {cout<<"Human's test"<<endl; return this; }
};
class Englishman : public Human {
public:
    void eating(void) { cout<<"use knife to eat"<<endl; }
    virtual ~Englishman() { cout<<"~Englishman()"<<endl; }
    virtual Englishman* test(void) {cout<<"Englishman's test"<<endl; return this; }
};


class Chinese : public Human {
public:
    void eating(void) { cout<<"use chopsticks to eat"<<endl; }
    virtual ~Chinese() { cout<<"~Chinese()"<<endl; }
    virtual Chinese* test(void) {cout<<"Chinese's test"<<endl; return this; }
};

void test_eating(Human& h)
{
    h.eating();
}

void test_return(Human& h)
{
    h.test();//test函数的返回值为对象的指针,可以实现多态
}

int main(int argc, char **argv)
{
    Human h;
    Englishman e;
    Chinese c;

    test_return(h);
    test_return(e);
    test_return(c);

    return 0;
}

c、只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。

d、静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。

e、内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。

f、构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值