C++继承性和多态性(五)

4.基类与派生类的转换:

  对于数值类型变量C++是一个弱类型语言。它允许不同类型的变量在一定的条件下进行转换:较小 类型的数值变量赋值给较大类型的数值变量。

  如,整型数=>双精度数(隐式类型转换)

  对于指针、引用、结构、类等类型变量C++又是一个强类型语言。它不允许不同类型的变量在同一表达式中出现。

        对于基类和派生类对象,C++允许通过公有继承方式联系起来的两个对象间进行隐式转换。

    隐式转换规则:

 

  与数值类型隐式转换的规则相反: 将“较大” 的对象(派生类对象)赋值给“较小”的对象(基类对象)

派生类对象可以向基类对象赋值

若定义两个对象:

     CPoint  point; //CPoint 基类

     CRect  rect;    // CRect 派生类

则:

     point = rect;     

        //O.K,派生类对象赋给基类对象

     rect = point;      

     //error,基类对象不能直接赋给派生类对象

    (CPoint)rect = point; 

             //O.K,派生类对象经过显式类型转换成基类对象

      rect = (CRect)point;  

 

             //error,基类对象不能显式转换成派生类


 

大材小用式赋值——派生类对象赋值给基类对象。

C++继承性和多态性(五)

说明:

  可以用公用派生类对象对其基类对象赋值,在赋值时舍弃派生类自己的成员。

  事实上,所谓赋值只是对数据成员赋值,对成员函数不存在赋值问题。

 

  请注意:赋值后不能企图通过基类对象访问派生类成员。

派生类对象可以代替基类对象向基类对象的引用进行初始化:

如,已定义了基类A对象a1,可以定义a1的引用:

--------------------------------------

A a1;  //定义基类A对象a1

B b1;  //定义公有派生类B对象b1

 

A&r=a1; //定义基类A对象的引用r,并用a1对其初始化

-------------------------------------------------------

A a1;  //定义基类A对象a1

B b1;  //定义公有派生类B对象b1

 

A&r=b1; //定义基类A对象的引用r,并用b1对其初始化

--------------------------------------------------------

!!!注意:此时r并不是b1的别名,也不与b1共享同一段存储单元。它只是b1中基类部分的别名,与b1中基类部分共享同一段存储单元。

如果函数的形参是基类对象或基类对象的引用,相应的实参可以用派生类对象:

如,有一函数fun()

void fun(A&r);  //形参是基类A对象的引用

cout<<r.num<<endl;

}

 

  //输出引用r所代表对象的数据成员num


A a1;

B b1; 

 

fun(b1);   //用派生类对象b1作实参传递数据

    !!!注意:由于基类和派生类对象能自动隐式转换,故可以用b1代替a1作为实参。此时输出的是派生类B对象b1中的基类数据成员num

派生类对象的地址可以赋值给基类对象的指针变量,或说,指向基类的指针也可以指向派生类:

注意2点:

(1)指向不同数据类型的指针和引用是不能互相转换的。这一点对指向不同类对象的指针也适用。
(2)如果两个指针所指向的对象是通过公共继承方式相关联的话,则允许一定程度的赋值转换。

  转换规则:

(1)基类对象指针(或引用)赋值给派生类对象指针(或引用)时为不安全转换。

   因为,派生类对象指针将失去访问派生类成员的功能,会出现语法错误。

 

  p_b1 = p_a1; ×

   (2)派生类对象指针(或引用)赋值给基类对象指针(或引用)是安    全的。

      因为,派生类指针除了能够访问派生类的功能,还能访问基类    的功能。而基类指针仅仅只能访问基类的功能。

      此时,基类指针只能访问派生类从基类继承的功能,不能访问    派生类自身的功能。除非对基类指针作强制类型转换

      p_a1 = p_b1;     

 

     (B)p_a1 = p_b1;  


#include< iostream>

#include< string >

using namespace std;

  

class CPoint //基类Point类的声明

{private:

      int X,Y;

  public:

      CPoint(int a=0, int b=0) {X=a; Y=b;}

      void set(int a, int b) {X=a; Y=b;}

      void move(int a, int b) {X+=a; Y+=b;}

      void get(int &r_a,int &r_b) const 

{r_a=X,r_b=Y;}

};



//派生类声明

class CRect: public CPoint

{ private:

      int H,W;   //新增私有数据成员

   public:         //新增公有成员函数

      CRect(){CPoint::set(0,0);H=0;W=0;}

              //调用基类公有成员函数

      CRect(int left,int top,int w_val,int h_val)

      {CPoint::set(left,top);

        H=h_val;

        W=w_val; }

       void getSize(int &r_h,int &r_w) const

       {r_h=H;r_w=W;}

       void set(int left,int top,int w_val,int h_val) 

      {CPoint::set(left,top);

         W=w_val;

         H=h_val;

       }

        void print() const 

       { int top,left;

          get(left,top);

          cout<<"   left = "<<left<<"  top = "<<top<<endl;

        }

};


int main()

{  int h,w;

    CRect rect(20,30,40,50);   //定义一个派生类对象

     rect.getSize(h,w); //调用派生类对象成员函数

     cout<<"Rect height:"<<h<<" width:"<<w<<endl;


    CPoint point(10,10);   //定义一个基类对象

      point=rect;

      point.move(5,5);

//    point.print();

//    (CRect)point.print();


//    rect=point;

    (CPoint)rect=point;

    rect.print();


    CRect *p_rect=new CRect(10,20,10,10);    

    p_rect->getSize(h, w);     //用派生类指针调用派生类成员函数  

    cout<<"Rect height:"<<h<<"  width:"<<w<<endl;

    p_rect->move(10, 20);    //用派生类指针调用基类成员函数

    p_rect->print();      


   CPoint *p_point=p_rect; 

    p_point->move(10, 20);   

//    p_point->print();

    ((CRect *)p_point)->print();


    p_point=new CPoint(10,20); 

//    p_rect->p_point;   

    p_point->set(30,40);

    ((CRect *)p_point)->print();


    delete p_point;

    delete p_rect;

    

    return 0;

 

}

  指针(引用)之间: 

派生类对象指针可以直接赋值给基类指针;(引用)      p_point=p_rect;

    赋值后的基类指针并不能访问派生类对象成员;除非经过显式的类型转换

  p_point->show(); ×

     (Crect *)p_point->show();

基类对象指针不能直接赋值给派生类对象指针。

 

   p_rect=p_point; ×

  指针(引用)之间: 

派生类对象指针可以直接赋值给基类指针;(引用)      p_point=p_rect;

    赋值后的基类指针并不能访问派生类对象成员;除非经过显式的类型转换

  p_point->show(); ×

     (Crect *)p_point->show();

基类对象指针不能直接赋值给派生类对象指针。

 

   p_rect=p_point; ×


类对象、对象指针、对象引用转换的必要条件:

 

基类和派生类必须是通过公有继承方式联系起来的,则相互之间可以进行隐式类型转换和赋值。


posted @ 2014-05-18 19:45  dreamsyeah  阅读(136)  评论(0编辑  收藏  举报