多态性(三)

本文探讨了C++中的多态性和运算符重载两大特性。详细讲解了虚函数、析构函数及纯虚析构函数的概念,并通过示例展示了如何利用运算符重载实现不同类型对象之间的运算。

七. 虚函数和构造函数

        当创建一个包含有虚函数的对象时,必须初始化它的VPTR以指向相应的VTABLE。这必须在对虚函数进行任何调用之前完成,显然这是构造函数的工作。编译器在构造函数的开头部分秘密地插入初始化VPTR的代码。

        构造函数的初始化顺序和普通的情况一样,基类构造函数首先调用。不过,如果我们在构造函数中调用了虚函数会发生什么?对于在构造函数中调用一个虚函数的情况,被调用的只是这个函数的本地版本,也就是说,虚机制在构造函数中不工作。

        构造函数是不能为虚函数的。但析构函数能够且常常必须是虚的。

//Behavior of virtual vs. non-virtual destructor
#include <iostream>
using namespace std;

class Base1
{
public:
           
~Base1() { cout<<"~Base1() "; }
};

class Derived1 : public Base1
{
public:
           
~Derived1() { cout<<"~Derived1() "; }
};

class Base2
{
public:
             
virtual ~Base2() { cout<<"~Base2() "; }
};

class Derived2 : public Base2
{
public:
            
~Derived2() { cout<<"~Derived2() "; }
};

int main()
{
        Base1
* bp=new Derived1;        //Upcast
        delete bp;
        Base2
* b2p=new Derived2;    //Upcast
        delete b2p;
        cout
<<"end of file"<<endl;
}

        通常,析构函数的执行是相当充分的。但是,如果想通过指向某个对象基类的指针操纵这个对象,会发生什么现象呢?这在面向对象的程序设计中确实很重要。当我们想delete在栈中已经用new 创建的对象的指针时,就会出现这个问题。如果这个指针是指向基类的,在delete期间,编译器只能知道调用这个析构函数的基类版本。因此,不把析构函数设为虚函数是一个隐匿的错误。

        纯虚析构函数: 纯虚析构函数在标准C++中是合法的,但在使用时有一个额外的限制:必须为纯虚析构函数提供一个函数体。它的主要作用是阻止基类的实例化。

八. 运算符重载    

//Polymorphism with overloaded operators
#include <iostream>
using namespace std;

class Matrix;
class Scalar;
class Vector;

class Math
{
public:
       
virtual Math& operator*(Math& rv) = 0;
       
virtual Math& multiply(Matrix*= 0;
       
virtual Math& multiply(Scalar*= 0;
       
virtual Math& multiply(Vector*= 0;
       
virtual ~Math() {}
};

class Matrix : public Math
{
public:
        Math
& operator*(Math& rv)
        {
                   
return rv.multiply(this);    //2nd dispatch
        }
        Math
& multiply(Matrix*)
        {
                  cout
<<"Matrix * Matrix"<<endl;
                  
return *this;
        }
        Math
& multiply(Scalar*)
        {
                  cout
<<"Scalar * Matrix"<<endl;
                  
return *this;
         }
         Math
& multiply(Vector*)
         {
                  cout
<<"Vector * Matrix"<<endl;
                  
return *this;
         }
};

class Scalar : public Math
{
public:
          Math
& operator*(Math& rv)
          {
                    
return rv.multiply(this);
          }
          Math
& multiply(Matrix*)
          {
                   cout
<<"Matrix * Scalar"<<endl;
                   
return *this;
          }
         Math
& multiply(Scalar*)
         {
                    cout
<<"Scalar * Scalar"<<endl;
                    
return *this;
         }
         Math
& multiply(Vector*)
         {
                    cout
<<"Vector * Scalar"<<endl;
                    
return *this;
         }
};

class Vector : public Math
{
public:
           Math
& operator*(Math& rv)
           {
                    
return rv.multiply(this);
            }
            Math
& multiply(Matrix*)
            {
                       cout
<<"Matrix * Vector"<<endl;
                        
return *this;
            }
            Math
& multiply(Scalar*)
            {
                      cout
<<"Scalar * Vector"<<endl;
                      
return *this;
             }
             Math
& multiply(Vector*)
             {
                        cout
<<"Vector * Vector"<<endl;
                        
return *this;
             }
};

int main()
{
              Matrix x;
              Vector v;
              Scalar s;
              Math
* math[]={&x,&v,&s};
              
for(int i=0;i<3;i++)
                    
for(int j=0;j<3;j++)
                   {
                              Math
& m1=*math[i];
                              Math
& m2=*math[j];
                              m1
*m2;
                   }
}

        这里只是给出一个比较简单的重载。重载的目的是使任意两个Math 对象相乘并且生成所需的结果。main()中的问题在于,表达式m1*m2 包含两个向上类型转换的Math 引用,因此不知道这两个对象的类型。一个虚函数仅能进行单一指派——即判定一个未知对象的类型。这个例子中所使用的判定两个对象类型的技术称之为多重指派(multiple dispatching),一个单一虚函数调用引起了第二个虚函数的调用。不过这是比较高级的主题了,这就不详述了。

小结:

        多态,这是C++实现面向对象的一个很重要的特性,它意味着"具有相同的形式,实现不同功能"。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值