派生类的对象都含有基类对象作为其一部分,我们可以将指向派生类型的引用转换为指向它的基类型的引用,像转换指针一样,我们可以用派生类的对象初始化或赋值基类对象,反之却不行。class base{
public:
};
class derived:public base{
public:
};
int main(void) {
derived obj_d;
base obj_b=obj_d;//赋值运算符
base obj_b2(obj_d);//用派生类对象初始化
derived &ref_d=obj_d;
base &ref_b=ref_d;
base &ref_b2(ref_d);
cout<<"end in main\n";
return EXIT_SUCCESS;
}
程序编译没有错误,只是会提示ref_b,ref_b2没有使用,如果反过来转换基类对象或引用为派生类型的则会报错。
实际上,这里编译器并没有将派生类对象或引用“转换”为基类型的,只是用派生类对象中的基类部分初始化或赋值基类对象,引用方面,将派生类基类部分的地址传递给基类型的引用。
前面在虚函数实例时,看到将派生类对象传递给参数为基类型引用的函数,这时传递的是地址,实参的派生类对象还是派生类对象。
如果是参数为基类对象的函数,情况有所不同,实参派生类对象的基类部分会被复制给一个函数体内建立的临时的基类对象。
当我们用派生类对象初使化或赋值基类对象时,有两种可能:
1.基类中定义了相应的构造函数和重载了赋值运算符,这时将会按照相应的函数进行
class derived;
class base{
public:
base(const derived&);
base& operator=(derived &);
};
2.基类中并没有定义相关的函数,与情况1相比,这种情况更为常见。
通常基类中会有考构,其参数为const 基类型引用,考构会帮我们完成派生类对象初始化或赋值基类型对象,其中发生指向派生类的引用转换为基类型的引用。开头的示例程序:
base obj_b=obj_d;//赋值运算符
base obj_b2(obj_d);//用派生类对象初始化,调用的构造函数
派生类中的基类部分好像被“切割”(slice down)下一样,赋值给基类对象。
派生类-基类 转换后的成员访问问题
如果是公有派生,转换后,可以访问基类对象的相应成员,如果是保护或私有派生则不可。
class base{
public:
int pub;
protected:
int pro;
};
class derived:public base{
public:
};
int main(void) {
derived obj_d;
base obj_b=obj_d;//赋值运算符
cout<<obj_b.pub<<" "<<endl;
cout<<"end in main\n";
return EXIT_SUCCESS;
}
程序没有任何问题,输出结果为一随机值,因为我们没有定义任何构造函数为数据成员初始化。
如果将派生类型变为保护或私有
class derived:protected base{
public:
};
编译报错 `base' is an inaccessible base of `derived'
而且,私有派生时,其后续派生的类是不可转换为基类型的,保护派生可以。
基类-派生类 的转换
无论是用基类对象还是引用初始化派生类对象或引用都是不可以的,基类对象其所占的内存空间中并没有派生类所定义的只属于它自己的那一部分。即使是有一个基类型的引用,其此时正好指向一个派生类对象,我们也不可将其转换为派生类型的引用,因为编译时编译器检查的是静态类型。