C++把子类对象当基类对象使用

★当公有继承的时候,子类对象可以当基类对象来使用。

①把一个子类对象赋值给基类对象;
例:
 class Base;
 class Derived:public Base;

 Derived d;
 Base b;

 b=d;  //OK,子类可以赋值给基类(把子类的基类部分赋值给基类);
 d=b;  //ERROR,基类不可以赋值给子类(子类中含有自己的附加部分,而基类没有);

②基类引用引用一个子类对象;

a.用子类对象初始化一个基类引用;
例:
 Base &b=d;

b.子类对象被用作函数的参数,这个参数接受一个基类的引用;
例:
 func(Base& b);
 func(d);

c.返回值是一个基类的引用却返回了一个子类;
例:
 Base& func(){return d;}

▲当基类引用引用子类的时候,表现的是基类的行为。或者说定义在子类的成员和成员函数不能被基类进行访问。

例:
 Base &b=d; //b是子类对象,但是b的行为是基类行为(只能调用子类继承来的基类部分的方法,不能调用子类附加部分的方法);

▲特殊情况下,假如子类覆盖了基类的某些函数,引用时依然调用基类的函数。
例:
 class Base
 {
 public:
  func(){cout<<"b"<<endl;}
 };
 
 class Derived:public Base
 {
 public:
  func(){cout<<"d"<<endl;}
 };

 Base& b=d;
 b.func(); //调用Base类的func()方法;

▲函数在接受一个基类引用或者返回一个基类引用,其依然表现基类行为(不能访问子类的附加部分);
例:
 fun(Base& b){
   b.fun();
   }
 fun(d);  //调用Base类的func()方法;
 
▲拷贝构造可以接受一个基类引用,但是我们可以引用一个子类对象,拷贝构造出口来的还是一个基类对象;
例;
 Base(const Base& b);
 Base b1(d); //拷贝构造出来的b1是一个基类对象;

▲传值;
例:
 func2(Base b){
   b.func();
   }
 
 func2(d) //传值调用拷贝构造,结果构造了一个基类对象;

▲返回值;  //返回基类;
例:
 Base func3(){
   return d; 
   }

③基类指针可以指向一个子类对象;

a.子类地址赋值给基类指针;
例:
 Base* p=&d;

b.子类指针赋值给基类指针;
例:
 Base* b;
 Derived* d;
 b=d;

c.子类对象传递给函数;
例:
 func(Base* b);
 Derived d;
 func(&d);

d.子类地址返回,函数返回基类指针;
例:
 Base* func();
 func(){return d;}

***可以用一个基类指针引用一个子类指针,这种情况经常发生在函数传参;

***以通过基类指针还是基类指针的引用,这时还是基类行为,指向一个子类对象;

★基类对象不能当子类对象使用(因为基类对象没有子类对象的附加部分)。然而一个基类指针指向一个子类对象,表现出基类行为。
例:
 Base* b=&d;
 b.func(); //输出b;
 static_cast<Derived*>(b).func()  //静态强制转化,输出d;
 (Derived*)b.func()   //同上;


★基类指针可以转换成子类指针(很危险,最好不用)。要保证不出错需要基类的指针指向子类的对象的地址,或者基类对象是子类对象的引用。
例:
 Base* b;    //基类的指针指向子类对象的地址;
 Dericed d;
 b=&d;
 (Derived*)b->fun();

 Base& b=d;    //基类对象是子类对象的引用;
 b.fun();
 ((Derived&)b).fun()


★总结:
 基类不能以任何形式赋给子类。传递啥无所谓,看定义的是啥类型就是啥类型,叫表现啥类型的行为。(虚函数不适用)

展开阅读全文

没有更多推荐了,返回首页