多态性(三)

七. 虚函数和构造函数

        当创建一个包含有虚函数的对象时,必须初始化它的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、付费专栏及课程。

余额充值