继承
一、继承是什么
通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类称为基类(Base Class)或者父类。由基类派生出的新类称为派生类(Derived Class ),又称为子类。继承也是代码复用最重要的手段。
二、生活中的继承
类的继承与派生是一个从抽象到具体的过程。什么是抽象的过程呢?我们举个例子,“表”是可以用来记时间的,这是我们对表的第一印象。那么表到底是圆的还是方的? 大的还是小的呢?这也没有同意的规定,这是因为“表”是一个抽象的概念,没有任何指定的实体,这在面向对象领域中被称为抽象类。
以“表”为父类(基类),派生出“手表”,手表不仅继承了表的特点,而且更加具体。手表,个头不大,戴在手上,由机芯、表盘、表带等组成,当然表还是不够具体。
接着继承手表类,派生出“百达翡丽Patek Philippe系列5146R-001机械男表”,此时就属于具体类了,它拥有父类手表的所有特点,同时还派生出其他数据,名牌型号价格等。在c++中这块表被称为实例,也叫做对象。
二、继承的定义格式
class 派生类名字:继承类型 基类名字....
// 基类
class Base
{
public:
Base()
{
cout << "Base Class" << endl;
}
};
// 派生类
class DerivedClass:public Base
{
public:
DerivedClass()
{
cout << "Derived Class" << endl;
}
};
三、继承关系和访问限定符
三种访问限定符:
public:可以被任意实体访问
protected:只允许子类及本类的成员函数访问
private:只允许本类的成员函数访问
现有如下代码实例:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base()" << endl;
}
~Base()
{
cout << "~Base()" << endl;
}
void BaseShow()
{
cout << "b_public = " << b_public << endl;
cout << "b_protected = " << b_protected << endl;
cout << "b_private = " << b_private << endl;
}
public:
int b_public;
protected:
int b_protected;
private:
int b_private;
};
class Derived:protected Base
{
public:
Derived()
{
cout << "Derived()" << endl;
}
~Derived()
{
cout << "~Derived()" << endl;
}
void DerivedShow()
{
cout << "b_public = " << b_public << endl;
cout << "b_protected = " << b_protected << endl;
cout << "b_private = " << b_private << endl;
cout << "_d_public = " << _d_public << endl;
cout << "_d_protected = " << _d_protected << endl;
cout << "_d_private = " << _d_private << endl;
}
public:
int _d_public;
protected:
int _d_protected;
private:
int _d_private;
};
先来一张表概括一下,然后我们去一一验证。
(1)当继承方式是public时,在派生类中访问成员图如下:
在测试函数Test(也就是类外)中访问派生类成员如下:
我们可以看到,基类的private成员在派生类和类外都是无法访问的,而基类的protected成员却可以在派生类中访问,但无法在类外直接被访问。public成员访问权限没有变化,类外和派生类内都可以访问,也验证了表中public继承基类的非私有成员在子类的访问属性都不变
如果基类成员不想在类外被直接访问,但需要在派生类中访问,就定义为protected,可以看出保护成员限定符也是因为继承才出现的。
(2)当我们把继承方式改为protected时,在派生类中访问成员图如下:
可以看出,改为protected继承后,派生类依旧可以访问基类中处private成员之外的数据。
在测试函数Test中访问派生类成员如下:
改为protected继承后,在类外只能访问派生类的protected成员,而我们在public继承中可以在类外访问的基类public成员此时在类外却无法访问,于是我们可以得出:protected继承将基类的非私有成员都变为子类的保护成员。
(3)当我们把继承方式改为private时,在派生类中访问成员图如下:
看到这里是不是发现这三种继承方式中派生类可以访问的成员一模一样?
没错,我们又发现了一个结论:不管是那种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员在内存中存在,但在子类中不可见,编译器对我们做出了限制。
在测试函数Test中访问派生类成员如下:
看到这里可能又要蒙了,怎么私有继承和保护继承派生类访问权限一样,在类外也还是一样,那这两个到底有什么区别呢?下面我们来揭秘。
我们在定义一个类C继承Derived如下:
class C:public Derived
{
C()
{
cout << "b_public = " << b_public << endl;
cout << "b_protected = " << b_protected << endl;
cout << "b_private = " << b_private << endl;
cout << "_d_public = " << _d_public << endl;
cout << "_d_protected = " << _d_protected << endl;
cout << "_d_private = " << _d_private << endl;
};
现在我们来看看在类C内访问权限是怎么样的:
下图是Derived 类protected 类Base时 ,在Derived的派生类C内的访问权限:
再来看看Derived 类private类Base时 ,在Derived的派生类C内的访问权限:
可以看到在Derived的派生类C内,无法去访问基类公开,保护已经私有的任何成员,那这个时候我们又可以得出一个结论:
private继承使得基类所有成员在子类中的访问权限变为private。所以在C类中才会无法访问基类Base的public成员和protected成员。
温馨提示:在c++中class和struct的唯一不同就是不加访问限定符的时候,类中的成员默认是private修饰,和struct中默认是public修饰。