zoukankan      html  css  js  c++  java
  • C++虚函数和纯虚函数

    虚函数是动态多态性的基础,其调用的方式是动态连篇(简单解释为只有在程序运行时才决定调用的是基类还是基类的派生类,系统会根据指针指向的对象来决定要调用的函数)

    非虚函数与其相反,是静态连篇(简单解释为在编译时期就已经决定了要调用的函数)

    class Shape
    {
       public:
           Shape(){};
           void draw()
           {
               cout <<"画图形"<<endl;
           }
    };
    class Rectangle:public Shape
    {
       public:
           Rectangle(){};
           void draw()
           {
               cout <<"画方形"<<endl;
           }
    
    };
    
    class Circle:public Shape
    {
       public:
           Circle(){};
           void draw()
           {
               cout <<"画圆形"<<endl;
           }
    
    };
    
    int main()
    {
        Shape *s;
        s=new Rectangle();
        s->draw();
        s=new Circle();
        s->draw();
        return 0;
    }

    我主程序中的意思是要画方形和画圆形,可执行的结果都是画图形(叫你两儿子出来,怎么出来的都是你啊,扯淡么),这很明显不符合我们的要求和多态的要求。所以虚函数必须应运而生。

    class Shape
    {
       public:
           Shape(){};
           virtual void draw() //注意这里设置为虚函数
           {
               cout <<"画图形"<<endl;
           }
    };
    class Rectangle:public Shape
    {
       public:
           Rectangle(){};
           void draw()
           {
               cout <<"画方形"<<endl;
           }
    
    };
    
    class Circle:public Shape
    {
       public:
           Circle(){};
           void draw()
           {
               cout <<"画圆形"<<endl;
           }
    
    };
    
    int main()
    {
        Shape *s;
        s=new Rectangle();
        s->draw();
        s=new Circle();
        s->draw();
        return 0;
    }

    这就满足我们了,一个是画方形,一个是画圆形。

    发现:即使不在基类shape当中把draw设置为虚函数,我们只要直接在主函数当中直接声明子类的对象,调用draw,这种情况下是符合多态的思想的。

    这就有疑问了,为什么还需要virtual关键字(虚函数)的存在呢?

    上面的例子只是一个两个派生类,如果shape有成百上千个派生类,难道我们调用派生类的draw的时候都声明一个派生类的对象吗?很明显不可能,所以虚函数的情况下,我们只要声明一个shape的指针就好了。

    上面枚举的Shape类里面有个draw函数,我们用得上吗?用在哪里?感觉糊里糊涂的,只知道用个虚函数就够了。其实我们根本用不到Shape里面的draw函数,也没有必要将它具体化。因此有必要在基类Shape当中,将draw函数的定义除去(用纯虚函数代替),而将它的定义留给派生类。

    例如:

    class Shape
    {
       public:
           Shape(){};
           virtual void draw()=0;
    };

    析构函数与虚函数的联系

       关于虚函数,在多态当中,一定要将基类的析构函数设置为虚函数并将其实现,只有这样,才能够达到按对象构造的逆序来析构对象;否则,析构的时候只会析构派生类那一部分,那么基类的那一部分就无法成功析构了。也就是是说只进行了“局部销毁”对象,这样可能会导致资源泄露、败坏之数据结构、在调试上面浪费许多时间。

    析构函数的主要作用:负责类内的资源的释放

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using  namespace std;
    
    class Shape
    {
       public:
           Shape(){};
           virtual void draw()=0;
           virtual ~Shape()
           {
               cout << "shape类析构" <<endl;
           }
    };
    class Rectangle:public Shape
    {
       public:
           Rectangle(){};
           void draw()
           {
               cout <<"画方形"<<endl;
           }
           ~Rectangle()
           {
               cout << "Rectangle类析构" <<endl;
           }
    };
    
    class Circle:public Shape
    {
       public:
           Circle(){};
           void draw()
           {
               cout <<"画圆形"<<endl;
           }
           ~Circle()
           {
               cout << "Circle类析构" <<endl;
           }
    };
    
    int main()
    {
        Shape *s;   //只进行了定义,尚未开辟空间
        s=new Rectangle();
        s->draw();
        delete s;  
        s=new Circle();
        s->draw();
        delete s;
        return 0;
    }

    记住:

    1、带多态性质的base class应该声明一个虚函数(最好是纯虚函数),同时也要声明一个virtual析构函数。如果class带有任何虚函数,它就应该拥有一个virtual析构函数。

    2、class的设计目的如果不是作为base class使用,或者不是为了具备多态性,就不该声明virtual析构函数。

  • 相关阅读:
    第十九节,使用RNN实现一个退位减法器
    深度学习系列经典博客收藏
    第十八节,TensorFlow中使用批量归一化(BN)
    第十七节,深度学习模型的训练技巧-优化卷积核,多通道卷积
    第十六节,使用函数封装库tf.contrib.layers
    第十五节,利用反卷积技术复原卷积网络各层图像
    第十四节,TensorFlow中的反卷积,反池化操作以及gradients的使用
    第十三节,使用带有全局平均池化层的CNN对CIFAR10数据集分类
    第十二节,TensorFlow读取数据的几种方法以及队列的使用
    在hadoop集群添加了slave节点的方法
  • 原文地址:https://www.cnblogs.com/kane0526/p/3585299.html
Copyright © 2011-2022 走看看