继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行拓展,增加功能。这样产生的新类成为派生类或者子类,被继承的类称为基类或者父类。
- 继承定义格式:
因为类成员访问限定符有三种,所以继承关系也有三种,分别是public、protected和private。
具体就不举例了,方便记住就是继承选择更安全的方向,成员安全属性只能提高,不能降低。比如使用public方式继承,所有成员属性都不改变,因为public访问权限是最低的,都可以访问。这里只需要注意,无论任何继承方式,父类的private成员始终是不可见的,也就是父类独有的。
- 派生类的默认成员函数
在继承关系中,在派生类中如果没有显示的定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数。
- 构造函数
- 拷贝构造函数
- 析构函数
- 赋值操作符重载
- 取地址操作符重载
- const修饰的取地址操作符重载
- 继承关系中构造函数调用顺序
就是在创建一个子类时,先调用基类的构造函数,再调用派生类的构造函数。
比如我们创建一个父类
class Father
{
public:
Father()
{
cout << "i am father" << endl;
}
};
在创建一个它的派生类
class Son:public Father
{
public:
Son()
{
cout << "i am son" << endl;
}
};
可以看到父类的构造函数先调用而派生类的构造函数后调用。
- 继承关系中析构函数调用顺序
析构函数就不放父类和子类的代码了,我们只看结果。
我们可以看到析构函数的调用刚好与构造函数相反,子类的析构先调用。
- 继承与转换
- 子类对象可以赋值给父类对象
- 父类对象不能赋值给子类对象
- 父类的指针/引用可以指向子类对象
- 子类的指针/引用不可以指向父类对象
由上图可以证明1,2点是正确的。
由上图可以证明3,4点是正确的。
- 友元关系不能继承
- 继承与静态成员
基类定义了static成员,则整个体系中只有一个这样的成员,无论派生多少个子类,都只有一个该成员实例。
- 单继承。多继承、菱形继承
单继承就是正常的一个子类继承一个父类。
多继承则为一个子类继承多个父类,继承方式与单继承类似。
菱形继承则为新类继承的两个父类继承了相同的父类,导致拥有同名成员的情况。
class A
{
public:
int A;
};
class B1 :public A
{
public:
int B1;
};
class B2 :public A
{
public:
int B2;
};
class C :public B1, public B2
{
public:
int C;
};
我们在这里创建一个简单的菱形继承关系。很明显我们能够看到B1,B2同时继承了A后都拥有A成员,那么C又同时继承了他们,那说明C就继承了两个A。也就是我们所说的二义性问题。
- 虚继承
上述二义性问题,当我们不使用虚继承时
可以看到这里C的A是有争议的,当然这里可以加域解析符来区分到底是B1还是B2中的A,但依然不方便。
这里我们就可以了解一下虚继承,关键字为virtual
我们发现当我们使用虚继承后,就可以直接访问了。
因为虚继承就是对于继承的重复成员只保留一份,解决了冗杂和二义性的问题。