纯虚函数、虚函数和非虚函数

来源:互联网 发布:美橙互联怎么解析域名 编辑:程序博客网 时间:2024/05/19 18:43

纯虚函数、虚函数和非虚函数

    1.纯虚函数(pure virtual function)

        纯虚函数的意义在于只继承接口。

        纯虚函数通常采用后接“=0”来实现,由于只是提供一个接口给派生类,因此无需定义,只需要一个声明式即可(析构函数除外,它要求必须提供函数定义)。例如:

        class Test

        {

             public:

                 virtual func() const =0;    //声明一个纯虚函数

        };

        对于含有纯虚函数的基类都被称为抽象类,所以不能定义一个对象实体。

       Test t;                                     //Error:Test为抽象类

        因此,所有继承自抽象类的派生类,必须对抽象类中所包含的的纯虚函数提供一份实现,这也是实现接口继承的关键。

        2.虚函数(virtual function)

          虚函数的意义在于提供一个接口以及一个默认的实现,后续的派生类既可以选择这个默认实现(不予另外定义)或者自己再定义出一份实现。

          class Base

          {

               public:

                    virtual f()  { cout<<"Default Function!"<<endl;}

          };

          class Derived:public Base

          {

               public:

                     virtual f() { cout<<"My own Function~"<<endl;}

          };

         这里的派生类Derived继承自Base,但并没有利用Base类中所提供的函数f的默认实现,而是又提供了函数f的实现,如果不提供的话,则所有基于派生类Derived的f函数调用都将使用基类中提供的默认实现。

        值得一提的是:绝不重新定义继承而来的缺省参数值。

        考虑下面这个例子:

         class Base
         {
              public:
                  virtual void print(int val=100) const
                   {
                        cout<<"Base default value is "<<val<<endl;
                   }
          };
         class Derived:public Base
         {
              public:
                  virtual void print(int val=111) const
                  {
                        cout<<"Derived default value is "<<val<<endl;
                  }
         };

      这里,无论你是定义一个对象还是一个对象指针,

           Base b;             //或者 Base* pb=new Base;

           Derived d;         //或者 Derived* pd=new Derived;

      只要其静态类型(即声明类型)与动态类型(即实际对象类型)保持一致,那么调用上述print函数就不会出现问题,但如果两者不一致,则

           Base* p=new Derived;

           p->print();        //输出结果为:Derived default value is 100

      而实际上,设定的Derived对象的print函数的默认参数值却是111.这是为什么呢?

      其实,原因就在于缺省参数值都是静态绑定的。正如上例,指针p的静态类型为Base*,因此其缺省值也是从静态类型而得到(即100),虽然执行的print函数仍为Derived作用域的print函数,但其默认值却是Base作用域的缺省参数,这也就可以解释上述结果产生的原因。因此,作为建议,永远不要重新定义继承而来的缺省参数。

        3.非虚函数(non-virtual function)

            非虚函数的意义在于继承接口,并继承一份强制性的实现。

            因此引出来的一个话题是:绝不重新定义继承而来的非虚函数。

            仍然是上面的例子,可以去掉上述的函数参数以及virtual属性,并用下述方式进行调用:

            Derived d;

            Base* pb=&d;

            pb->print();

            Derived* pd=&d;

            pd->print();              //动态类型均未Derived*,而静态类型不同

           所产生的结果一样么?当然,不一样。pb将会调用Base的print函数,而pd会调用Derived的print函数。对于同样的对象,却得到不同的调用结果,确实很奇怪。其实,仔细观察就会发现,调用函数完全取决于对象的静态类型,也就是说,非虚函数是静态绑定的。

           所以,永远不要试图重新定义继承而来的非虚函数,定义函数非虚意味着函数的不变性凌驾于其特异性,而试图重新定义恰恰违反了这个原则,如果特异性凌驾于不变性的话,为何不直接将其定义为虚函数呢~