C++通过类派生(Class Derivation)的机制支持继承(Inheritance)。允许程序员在保持原有类特性的基础上进行扩展,增加功能,派生出新类。
继承的方式有以下2种:单一继承和多重继承。
派生类的定义中包括子类新增加的成员和继承父类需要重写的成员。C++允许在派生类中重新声明和定义这些成员函数,使这些函数具有新的功能,称之为重写或覆盖。重写函数起屏蔽、更新作用,取代基类成员,完成新功能。
测试一:子类继承基类的所有属性和函数,设基类函数和数据均为public类型,并且以public方式被继承,做如下测试。例如:
// test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
using namespace std;
class CBox
{
public:
CBox()
{
cout<<"调用CBox类的构造函数;"<
运行结果:
首先调用基类的构造函数,再调用子类构造函数。析构时先析构子类后析构基类。子类继承了基类的所有公有函数和成员,除了基类的构造、析构函数。
测试二:子类重写基类的函数
子类中重写基类的函数后,默认调用的是子类的函数!!!
1、子类中添加基类中同名但不同参数的函数,则基类的带参数的Setheight(double h)函数首先被调用!!!
则编译出错test.cpp(72): error C2660: “CColorbox::SetHeight”: 函数不接受 1 个参数:
class CColorbox:public CBox
{
public:
CColorbox()
{
cout<<"调用CColorbox类的构造函数;"<
,才能够对其(子类继承的函数)进行重载。
class CColorbox:public CBox
{
public:
CColorbox()
{
cout<<"调用CColorbox类的构造函数;"<
调用结果:子类中重写基类的函数后,默认调用的是子类的函数!!!
3、在子类中添加新的函数和数据成员,调用子类新功能:
class CColorbox:public CBox
{
public:
CColorbox()
{
cout<<"调用CColorbox类的构造函数;"<
运行结果:
三、数据成员的重载
因为成员重载后,基类和子类中各有一份相同的数据成员,调用那一个成员就成了一个需要讨论的问题,测试时采用对于类成员的显式调用完成显示。
实验结果证明:基类函数会调用基类的数据成员,子类的成员函数默认调用子类的数据成员!!!
class CColorbox:public CBox
{
public:
CColorbox()
{
cout<<"调用CColorbox类的构造函数;"<
显示运行结果:
1、若将test中调用基类的赋值函数注释掉,则显示基类长度中,成员变量为随机值;
2、若要调用基类的长度成员,则要进行显式引用,即CBox::length。
派生类的生成
仔细分析派生新类这个过程,实际是经历了以下步骤:
第一步是继承基类的成员,不论是数据成员,还是成员函数,除构造函数与析构函数外全部接收(即全部拷贝,虽然子类中覆盖后只是显示调用,但仍可调用),全部成为派生类的成员。
子类中访问基类成员的拷贝方式为:子类对象.基类名::基类成员。如:
colorbox.CBox::length。
第二步是重写基类成员。如果派生类声明了一个与基类成员函数相同的成员函数时,派生类中的新成员则屏蔽了基类同名成员,类似函数中的局部变量屏蔽全局变量。称为同名覆盖(Override)。
由code1分析:
1、子类中重写了基类中的同名函数,则基类的同名函数不会再出现在子类。
1)重写:void SetHeight(double h);或void SetHeight();则基类的void SetHeight(double h)函数将不能在子类中显式调用。 2)若子类中需要重载SetHeight函数,则需要先重写与基类同参、同名、同返回值的函数,再进行重载。
2、子类中重写了基类中的同名数据,则该数据成员在子类中也存在了一份拷贝,如 length,则,默认方式是:继承过来的基类函数调用基类中的拷贝length,若用子类函数则调用子类中的length。
第三步是定义新成员。新成员必须与基类成员不同名,是派生类自己的新特性。派生类新成员的加入使得派生类在功能上有所发展。这一步是继承与派生的核心特征。
第四步是重写构造函数与析构函数。因为派生类不继承基类的构造函数与析构函数,并且派生类的需要对新添加的数据成员进行必要的初始化,所以构造函数与析构函数需要重写。