向上转型是使用父类的引用或指针来调用子类的对象,或者我们可以说,将子类的引用或指针转换为父类的引用或指针的行为称为向上转换。
class Super
{
int x;
public:
void funBase()
{
cout << "父类函数";
}
};
class Sub:public Super
{
int y;
};
int main()
{
Super* ptr; // 父类指针
Sub obj;
ptr = &obj;
Super &ref; // 父类引用
ref=obj;
}
与向上转型相反的是向下转型,我们将父类的引用或指针转换为派生类的引用或指针。
在多重继承中,派生类继承自多个基类,因此,在多重继承中存在很多歧义。
class A
{
void show();
};
class B:public A
{
};
class C:public A
{
};
class D:public B, public C
{
};
int main()
{
D obj;
obj.show(); // 编译错误,对show()访问不明确
}
在这种情况下,B 类和 C 类都从 A 类继承函数 show()
,因此,D 类具有函数 show()
的两个继承副本,在 main() 函数中,当我们调用函数 show()
时,就会产生歧义,因为编译器不知道要调用哪个 show()
函数,因此,我们在继承类时使用 Virtual 关键字。
class B : virtual public A
{
};
class C : virtual public A
{
};
class D : public B, public C
{
};
C++ virtual继承的另一种名称是菱形继承,主要目的是用于解决从不同类继承来的同名数据成员在内存中有不同的拷贝,造成数据不统一的问题,将共同的基类作为虚基类,这时从不同的路径继承来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题
众所周知,每当实例化派生类对象时,总是会调用基类构造函数,但是在混合继承的情况下,如上例所述,如果我们创建类 D 的实例,则将调用以下构造函数:
这将导致对 A 类的构造函数的多次调用,这是不可取的。虽然virtual基类被多个子类继承,但是它只有一个实例,因此基类的构造函数只被调用一次,在我们的例子中是 D 类在实例化的时候调用的。 如果在类 B 或类 C 中调用初始化类 A 的构造函数,则在创建类 D 的对象时,它将不会再次被调用。