类层次中的类转换


一. 单基派生的情形:
对于
    class base
    {
    };
   
    class derived: public base        //public inheritance
    {
    };
有以下赋值兼容规则可以遵循:
1. 派生类对象可以赋值给基类对象
   但是,因为基类对象不具有派生类对象所具有的成员,因此基类对象不能赋值给派生类对象,强转也不行。
   derived d;
   base b;
   b = d;  // OK, 但是,会产生切割问题(即对象b不能访问对象d附加的功能)
   d = b; // error
   d = (derived)b; // error

2.派生类对象可以初始化基类的引用
   derived d;
   base& br=d; //OK
但是,如下语句却是错误的(原因同 "一.1"):
   base b;
   derived& d = b; // error: invalid initialization of reference of type 'derived&' from expression of type 'base'
  
3.
(1) 派生类对象的地址可以赋给指向基类的指针;
      derived d;
      base *pb=&d; //OK
      这样,指向基类的指针,可以用来指向派生类对象中从基类继承下来的成员,但不包括派生类中追加的成员,除非采用强制类型转换(见例1:convert_test1.cpp);
      而且,在这种情况下,调用的是基类的成员函数,除非派生类进行了虚函数继承(见例3:convert_test3.cpp)。
      /* 例1:convert_test1.cpp   */
      /* IDE环境: Dev-C++ 4.9.9.2 */
     
      #include
      class base
      {
          public:
                 base():i(0){ };
                 int get_i(){ return i; }
                 void set_i(int x){ i = x;}
                 void display_i(){ printf(" i = %d /n", i);}
          private:
                  int i;
      };
     
      class derived: public base        //public inheritance
      {
          public:
                 derived():j(0){ };
                 int get_j(){ return j; }
                 void set_j(int x){ j = x; }
                 void display_j(){ printf(" j = %d /n", j);}
          private:
                  int j;
      };
     
      int main()
      {
      derived d;
      base *pb=&d; //OK
      pb->get_i();
      //pb->get_j(); //compile error:  F:/devcpptest/devcpptest/convert_test1.cpp 'class base' has no member named 'get_j'
                     //指向基类的指针,可以用来指向派生类对象中从基类继承下来的成员,但不包括派生类中追加的成员,除非对基类指针采用强制类型转换
                    
      base *pb2 = &d;
      //pb2->set_j(4);            //compile error:  F:/devcpptest/devcpptest/convert_test1.cpp 'class base' has no member named 'set_j'
      //(derived*)pb2->set_j(4); //compile error:  F:/devcpptest/devcpptest/convert_test1.cpp 'class base' has no member named 'set_j'
      ((derived*)pb2)->set_j(4); //OK, 必须对基类指针进行强转,才可以访问派生类的成员
      
      pb2->display_i();         
      ((derived*)pb2)->display_j(); // OK,有必须对基类指针进行强转,才可以访问派生类的成员
     
          while(1);
      }
     
      运行结果:
        i = 0
        j = 4
     
     
(2) 但是,基类指针不能直接赋值给派生类指针,得用强制类型转换:
      base *pb = new b();
      derived *pd =  pb; // error: 基类指针不能直接赋值给派生类指针, 没有用强制类型转换
      derived *pd = (derived*)pb; // OK: 基类指针直接赋值给派生类指针, 采用强制类型转换
           
      具体的例子,见例2(convert_test2.cpp):
      /* 例2:convert_test2.cpp   */
      /* 对于例1中的两个类base和derived,进行如下的测试: */
      /* IDE环境: Dev-C++ 4.9.9.2 */
     
      int main()
      {
     
      base *pb = new base;
      //derived *pd =  pb; // error: 基类指针不能直接赋值给派生类指针, 没有用强制类型转换
      derived *pd = (derived*)pb; // OK: 基类指针不能直接赋值给派生类指针, 采用强制类型转换
     
      pd->get_i();
      pd->get_j();
     
      pd->set_i(3);
      pd->set_j(5);
     
      pd->display_i();
      pd->display_j();
      
      while(1);
      }
     
      运行结果:
        i = 3
        j = 5
       
       
      /* 例3:convert_test3.cpp   */
      /* IDE环境: Dev-C++ 4.9.9.2 */
      /* 虚函数继承举例 */
     
      #include
      class base
      {
          public:
                 base():i(0){ };
                 int get_i(){ return i; }
                 void set_i(int x){ i = x;}
                 void virtual display_i(){ printf(" base::display_i, i = %d /n", i);}  //虚函数
                
          private:
                  int i;
      };
     
      class derived: public  base        //public inheritance
      {
          public:
                 derived():j(0){ };
                 int get_j(){ return j; }
                 void set_j(int x){ j = x; }
                 void display_j(){ printf(" j = %d /n", j);}
                
                 void  display_i(){ printf(" derived::display_i,  i = %d /n", get_i());}
          private:
                  int j;
      };
     
      int main()
      {
      derived d;
      base *pb=&d; //OK
      pb->set_i(2);    // 调用基类的set_i方法。
      pb->display_i(); // 调用的是派生类的display_i方法,如果在基类中的display_i不定义成virtual,则调用的就是基类的display_i了。
     
          while(1);
      }
     
      //运行结果:
        derived::display_i,  i = 2
     
二.多基派生:

1.对于如下的类层次结构,
    class  base0 
    { protected : int  b0 ;} ;
   
    class  base1: public  base0
    { protected : int  b1 ; } ;
   
    class base2  : public  base0
    { protected : int  b2 ; } ;
   
    class  derived : public  base1 , public  base2
    {
           public :
               int  f ( ) ;
           private : float  d ;
    } ;
可以:
  (1) 隐含地把指向派生类的指针转换为指向基类的指针,如同单继承一样;
  (2) 指向基类的指针强制类型转换为指向派生类的指针如同单继承一样;
然而,在这种情况下,会产生如下的问题,称作“多重继承中对基类成员访问的二义性”:
    (1)当试图将指向派生类的指针(derived指针)转换为指向其间接公共基类指针(base0指针)时,C++编译器不知道是从哪一个路径(base1 还是 base2)继承,
      从而导致编译错误,即使采用强制转换也不行。
  (2) 同样,当派生类引用间接基类的成员时,由于有两份copy,分别来自base1 和 base2,所以编译器不知道引用的base0的成员是从哪里来的。
        如:在display()中,如下语句是错误的: printf(" base0::b0 = %d /n", b0);
 
2. 克服这种二义性的方法:
  (1) 对指针要显示地指明全路径。
  (2) 将指针先强制转换到不会产生二义性的基类。
  (3) 显示指明成员来自哪个类。
3. 程序举例:
       /* multiinherencetest.cpp   */
       /* 多基派生 */
       /* IDE环境: Dev-C++ 4.9.9.2 */
      
       #include
       class  base0 
       { protected : int  b0 ;} ;
      
       class  base1: public  base0
       { protected : int  b1 ; } ;
      
       class base2  : public  base0
       { protected : int  b2 ; } ;
      
       class  derived : public  base1 , public  base2
       {
              public :
                  int  display( )
                  {
                         //printf(" base0::b0 = %d /n", b0); // error F:/devcpptest/devcpptest/multiinherencetest.cpp reference to `b0' is ambiguous
                                                            // error F:/devcpptest/devcpptest/multiinherencetest.cpp:4 candidates are: int base0::b0 
                         printf(" base0::base1::b0 = %d /n", base1::b0); // OK
                  }  
              private : float  d ;
       } ;
      
       int main()
       {
           derived d;
           derived *pd = &d;
          
           base1 *pb1;
           base0 *pb;
          
           pb1 = pd;              // OK: 隐含地把指向派生类的指针转换为指向基类的指针。(和单继承一样)
           pb1 = (base1*)pb;      // OK:把指向基类的指针强制类型转换为指向派生类的指针。 (和单继承一样)
          
           pb = pb1;             //OK: 隐含地把指向派生类的指针转换为指向基类的指针。(和单继承一样)
          
           pd = (derived*)pb1;   //OK: 把指向基类的指针强制类型转换为指向派生类的指针。(和单继承一样)
          
           //pd = pb;           // compile error: F:/devcpptest/devcpptest/multiinherencetest.cpp invalid conversion from `base0*' to `derived*'
           //pd = (derived*)pb; // compile error: F:/devcpptest/devcpptest/multiinherencetest.cpp `base0' is an ambiguous base of `derived'
          
           //pb = pd;           // compile error: F:/devcpptest/devcpptest/multiinherencetest.cpp `base0' is an ambiguous base of `derived'
           //pb = (base0*)pd;   // compile error: F:/devcpptest/devcpptest/multiinherencetest.cpp `base0' is an ambiguous base of `derived'
          
           //用如下形式消除以上的错误:
           pb = (base0*)(base1*) pd;  //OK
          
           pd = (derived*)(base1*)pb; //OK
          
           pb = (base1*) pd;  //OK
  
           while(1);
           return 0;
       }
      
  
三. 含有公共虚基类的类层次结构:
    使用虚基类,在它的几条派生路径的汇合处,只产生一个copy,所以,就不会产生二义性。 对于公共虚基类的类层次结构,
可以:
  1. 派生类对象的地址可以直接赋给间接公共基类的指针,并且不需要进行强制类型转换;如,
     base0 *pb = &d  // OK
  2. 一个虚基类的引用,可以引用一个派生类的对象。如,
   base0 &rb = d;  // OK
但是:
  相反的转换是不可以的,即使使用指定路径的强制转换也不行。如,
  derived *pd = (derived*)(base1*)pb;  // compiler error
  因为系统进行内存分配时,虚基类中的数据成员在派生类对象中的布局与非虚基类时不同,所以不能将指向虚基类的指针(或引用)置回指向派生类。
3. 程序举例:

    /* multiinherencetest2.cpp   */
    /* 含有虚基类的多基派生 */
    /* IDE环境: Dev-C++ 4.9.9.2 */
   
    #include
   
    class  base0 
    { protected : int  b0 ;} ;
   
    class  base1: public  virtual base0
    { protected : int  b1 ; } ;
   
    class base2  : public  virtual base0
    { protected : int  b2 ; } ;
   
    class  derived : public  base1 , public  base2
    {
           public :
               int  display( )
               {
                      //printf(" base0::b0 = %d /n", b0); // error F:/devcpptest/devcpptest/multiinherencetest2.cpp reference to `b0' is ambiguous
                                                         // error F:/devcpptest/devcpptest/multiinherencetest2.cpp:4 candidates are: int base0::b0 
                      printf(" base0::base1::b0 = %d /n", base1::b0); // OK
               }  
           private : float  d ;
    } ;
   
    int main()
    {
       
        derived d;
       
        base0 *pb = &d;  // OK
       
        base0 &rb = d;  // OK      
       
        //derived *pd = (derived*)(base1*)pb; //compile error: F:/devcpptest/devcpptest/multiinherencetest2.cpp cannot convert from base `base0' to derived type `base1' via virtual base `base0'
       
        while(1);
        return 0;
    }

你可能感兴趣的:(C++,C++基本语法实践,inheritance,派生,类转换,基类,子类)