11_c++多态

来源:互联网 发布:大数据平台技术架构 编辑:程序博客网 时间:2024/06/07 21:25

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

原创粉丝点击