C++篇(11)继承
一、继承的概念及定义
1.1 继承的概念
继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类的基础上进行拓展,增加方法(成员函数)和属性(成员变量),从而产生新的类,称为派生类。继承是类设计层次的复用。
比如下面,我们把公共的成员都放到Person类当中,Student和Teacher类都继承了Person,就可以复用这些成员。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;class Person
{
public:void identity(){cout << "void identity()" << _name << endl;}
protected:string _name = "张三"; //姓名string _address; //地址string _tel; //电话int _age = 18; //年龄
};class Student :public Person
{
public:void study(){//...}
protected:int _stuid; //学号
};class Teacher :public Person
{
public:void teaching(){//...}
protected:string _title; //职称
};int main()
{Student s;Teacher t;s.identity();t.identity();return 0;
}
1.2 继承的定义
在上面的代码中,我们可以看到Person是基类(也称为父类),Student是派生类(也称为子类)
基类的private成员在派生类中都是不可见的,这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问。如果基类成员不想在类外面直接被访问,但是需要在派生类中访问,就定义为protected。
在实际运用中一般都是public继承,几乎很少使用protected/private继承,因为protected/private继承下来的成员都只能在派生类里面使用,实际中拓展维护性不强。
1.3 继承类模板
当基类是类模板时,需要指定一下类域,否则编译报错(如下图所示)
因为Stack<int>在实例化时,也实例化了vector<int>,但是模板是按需实例化,push_back成员函数并未实例化,所以编译器找不到。
正确代码如下:
#include <iostream>
#include <vector>namespace bit
{template<class T>class Stack : public std::vector<T>{public:void push(const T& x){vector<T>::push_back(x);} };
}int main()
{bit::Stack<int> st;st.push(1);st.push(2);st.push(3);return 0;
}
二、基类与派生类之间的转换
通常情况下,我们把一个类型的对象赋值给另一个类型的指针或者引用时,存在类型转换,中间会产生临时对象,所以需要加const。而public继承中,就是一个特殊的例外,派生类对象可以赋值给基类的指针 / 基类的引用,并且不需要加const。这里的指针和引用绑定的是派生类对象中的基类部分,如下图所示:
派生类对象可以赋值给基类对象,是通过基类的拷贝构造函数或者赋值重载函数完成的。这个过程就像是派生类自己定义部分成员切掉了一样,所以也被叫做切割或者切片。但是基类对象不能赋值给派生类对象。
三、继承中的作用域
在继承体系中,基类和派生类都有独立的作用域。因此,派生类和基类中是会出现同名成员的,而派生类会屏蔽基类对同名成员的直接访问,这种情况叫隐藏(在派生类成员函数中,可以使用 基类::基类成员 显示访问)。在实际中,继承体系里面最好不要定义同名成员。
注意:如果是成员函数的隐藏,