★当公有继承的时候,子类对象可以当基类对象来使用。 ①把一个子类对象赋值给基类对象; 例: 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() ★总结: 基类不能以任何形式赋给子类。传递啥无所谓,看定义的是啥类型就是啥类型,叫表现啥类型的行为。(虚函数不适用) |