[C++]类的继承与派生
继承性是面向对象程序设计的第二大特性,它允许在既有类的基础上创建新类,新类可以继承既有类的数据成员和成员函数,可以添加自己特有的数据成员和成员函数,还可以对既有类中的成员函数重新定义。利用类的继承和派生实现了更高层次的代码可重用性,符合现代软件开发的思想。
C++语言同时支持单一继承和多重继承。单一继承是指派生类只从一个基类继承而来;相应的,多重继承指派生类同时从两个或更多的基类继承而来。java只支持单一继承。
一. 派生类
派生类的定义格式如下:
class <派生类名>:[继承方式]<基类名1>
[,[继承方式]<基类名2>,...,[继承方式]<基类名n>]
{
<派生类新增的数据成员和成员函数定义>
};
说明:
(1)定义派生类关键字可以是class或者是struct,两者区别是:用class定义派生类,默认的继承方式是private,用struct定义派生类,默认的继承方式为public。新增加的成员默认属性也是class对应private属性,struct对应public属性。
(2)基类不能被派生类继承的两类函数是构造函数和析构函数。
二. 3种继承方式下基类成员在派生类中的访问属性

用下面的代码简单理解一下:
#include "stdafx.h"
#include<iostream>
using namespace std; class Base
{
private:
int priData;
protected:
int proData;
public:
int pubData;
}; class D1:private Base//私有继承
{
void f1()
{
//priData=1;//基类private成员在派生类中不可直接访问
proData=;//基类的protected成员在派生类中为private访问属性
pubData=;//基类的public成员在派生类中为private访问属性
}
}; class D2:protected Base//保护继承
{
void f2()
{
//priData=1;//基类private成员在派生类中不可直接访问
proData=;//基类的protected成员在派生类中为protected访问属性
pubData=;//基类的public成员在派生类中为protected访问属性
}
}; class D3:public Base//公有继承
{
void f3()
{
//priData=1;//基类private成员在派生类中不可直接访问
proData=;//基类的protected成员在派生类中为protected访问属性
pubData=;//基类的public成员在派生类中为public访问属性
}
}; int main()
{
Base obj;
//obj.priData=1;//对象不可访问Base类中private成员
//obj.proData=2;//对象不可访问Base类中protected成员
obj.pubData=;
D1 objD1;
//objD1.pubData=3;//private属性,不可访问
D2 objD2;
//objD2.pubData=3;//protected属性,不可访问
D3 objD3;
objD3.pubData=;//public属性,可以访问
return ;
}
基类的private成员函数虽然在派生类的成员函数中不可直接访问,但派生类的成员函数可以通过调用基类被继承的函数来间接访问这些成员。如果基类的函数被继承后在派生类中仍为public成员,则可以通过派生类对象直接调用。
先来看一下类成员的访问属性及作用:
| 访问属性 | 作用 |
| private | 只允许该类的成员函数及友元函数访问,不能被其他函数访问 |
| protected | 既允许该类的成员函数及友元函数访问,也允许其派生类的成员函数访问 |
| public | 既允许该类的成员函数访问,也允许类外部的其他函数访问 |
好了,继续通过代码来理解:
#include "stdafx.h"
#include<iostream>
using namespace std; class Base
{
private:
int priData;
protected:
int proData;
public:
int pubData;
//在类的定义中不能对数据成员进行初始化
void SetData()//为基类中的数据成员赋值
{
priData=;
proData=;
pubData=;
}
void Print()
{
cout<<"priData="<<priData<<endl;
cout<<"proData="<<proData<<endl;
cout<<"pubData="<<pubData<<endl;
}
}; class Derived:public Base
{
public:
void ChangeData()
{
SetData();
proData=;//在派生类的成员函数类可以访问基类的非私有成员
}
}; int main()
{
Base b;
b.SetData();
b.Print(); Derived d1;
d1.ChangeData();
d1.pubData=;
d1.Print(); return ;
}
程序运行结果如下:
三. 派生类的构造函数和析构函数
在定义一个派生类的对象时,在派生类中新增加的数据成员当然用派生类的构造函数初始化,但是对于从基类继承来的数据成员的初始化工作就必须由基类的构造函数完成,这就需要在派生类的构造函数中完成对基类构造函数的调用。同样,派生类的析构函数值能完成派生类中新增加数据成员的扫尾、清理工作,而从基类继承来的数据成员的扫尾工作也应有基类的析构函数完成。由于析构函数不能带参数,因此派生类的析构函数默认直接调用了基类的析构函数。
派生类构造函数定义格式如下:
<派生类名>(<总形式参数表>):<基类名1>(<参数表1>),
<基类名2>(<参数表2>),[...,<基类名n>(<参数表n>),其他初始化项>]
{
[<派生类自身数据成员的初始化>]
}
说明:
(1)总形式表给出派生类构造函数中所有的形式参数,作为调用基类带参构造函数的实际参数以及初始化本类数据成员的参数;
(2)一般情况下,基类名后面的参数表中的实际参数来自前面派生类构造函数形式参数总表,当然也可能是与前面形式参数无关的常量;
(3)在多层次继承中,每一个派生类只需要负责向直接基类的构造函数提供参数;如果一个基类有多个派生类,则每个派生类都要负责向该积累的构造函数提供参数。
1.单一继承
#include"stdafx.h"
#include<iostream>
using namespace std; class Other
{
public:
Other()
{
cout<<"constructing Other class"<<endl;
}
~Other()
{
cout<<"destructing Other class"<<endl;
}
}; class Base
{
public:
Base()
{
cout<<"constructing Base class"<<endl;
}
~Base()
{
cout<<"destructing Base class"<<endl;
}
}; class Derive:public Base
{
private:
Other ot;
public:
Derive()
{
cout<<"constructing Derive class"<<endl;
}
~Derive()
{
cout<<"destructing Derive class"<<endl;
}
}; int main()
{
Derive d; return ;
}
程序运行结果如下:

可以看到定义派生类对象时,构造函数的调用顺序:
a.先调用基类的构造函数
b.然后调用派生类对象成员所属类的构造函数(如果有对象成员)
c.最后调用派生类的构造函数
析构函数的调用顺序正好与构造函数调用顺序相反。
2.多重继承
#include"stdafx.h"
#include<iostream>
using namespace std; class Grand
{
int g;
public:
Grand(int n):g(n)
{
cout<<"Constructor of class Grand g="<<g<<endl;
}
~Grand()
{
cout<<"Destructor of class Grand"<<endl;
}
}; class Father:public Grand
{
int f;
public:
Father(int n1,int n2):Grand(n2),f(n1)
{
cout<<"Constructor of class Father f="<<f<<endl;
}
~Father()
{
cout<<"Destructor of class Father"<<endl;
}
}; class Mother
{
int m;
public:
Mother(int n):m(n)
{
cout<<"Constructor of class Mother m="<<m<<endl;
}
~Mother()
{
cout<<"Destructor of class Mother"<<endl;
}
}; class Son:public Father,public Mother
{
int s;
public:
Son(int n1,int n2,int n3,int n4):Mother(n2),Father(n3,n4),s(n1)
{
cout<<"Constructor of class Son s="<<s<<endl;
}
~Son()
{
cout<<"Destructor of class Son"<<endl;
}
}; int main()
{
Son s(,,,);
return ;
}
程序运行结果如下:
可以看到,与单一继承不同的是:在多重继承中,派生类有多个平行的基类,这些处于同一层次的基类构造函数的调用顺序,取决于声明派生类时所指定的各个基类的顺序,而与派生类构造函数的成员初始化列表中调用基类构造函数的顺序无关。
[C++]类的继承与派生的更多相关文章
- 模块的封装之C语言类的继承和派生
[交流][微知识]模块的封装(二):C语言的继承和派生 在模块的封装(一):C语言的封装中,我们介绍了如何使用C语言的结构体来实现一个类的封装,并通过掩码结构体的方式实 现了类成员的保护.这一部分,我 ...
- 09--c++ 类的继承与派生
c++ 类的继承与派生 一.基本概念 1.类的继承,是新的类从已有类那里得到已有的特性.或从已有类产生新类的过程就是类的派生.原有的类称为基类或父类,产生的新类称为派生类或子类. 2.派生类的 ...
- C++学习笔记:07 类的继承与派生
课程<C++语言程序设计进阶>清华大学 郑莉老师) 基本概念 继承与派生的区别: 继承:保持已有类的特性而构造新类的过程称为继承. 派生:在已有类的基础上新增自己的特性(函数方法.数据成员 ...
- Day 5-2 类的继承和派生,重用
类的继承 派生 在子类中重用父类 组合 抽象类 定义: 继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创建新类的方式,在python中,新 ...
- 4-13 object类,继承和派生( super) ,钻石继承方法
1,object 类 object class A: ''' 这是一个类 ''' pass a = A() print(A.__dict__) # 双下方法 魔术方法 创建一个空对象 调用init方法 ...
- Python基础(16)_面向对象程序设计(类、继承、派生、组合、接口)
一.面向过程程序设计与面向对象程序设计 面向过程的程序设计:核心是过程,过程就解决问题的步骤,基于该思想设计程序就像是在设计一条流水线,是一种机械式的思维方式 优点:复杂的问题的简单化,流程化 缺点: ...
- 对C++类的继承和派生的理解
C++中的继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承类似,例如儿子继承父亲的财产. 1.继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程. ...
- Python3 面向对象-类的继承与派生
1.什么是继承? 继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类可称为基类或超类,新建的类称为派生类和或子类. 子类会遗传父类的属性,从而解决代码重用问题. ...
- C++——类的继承(派生)
类的继承就是子类可以拥有父类的成员变量和成员函数 //public 修饰的成员变量 方法 在类的内部 类的外部都能使用//protected: 修饰的成员变量方法,在类的内部使用 ,在继承的子类中可用 ...
随机推荐
- Huffman树的编码译码
上个学期做的课程设计,关于Huffman树的编码译码. 要求: 输入Huffman树各个叶结点的字符和权值,建立Huffman树并执行编码操作 输入一行仅由01组成的电文字符串,根据建立的Huffma ...
- 说明一下JNI 与AIDL
代码在评论中. JNI: 为什么需要JNI: 因为android是由[JAVA & C/C++]组成.Java运行在Dalvik虚拟机中. 没有办法直接访问底层硬件.底层HW相关目前技术一般都 ...
- hdu 5104 Primes Problem
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5104 Primes Problem Description Given a number n, ple ...
- 26.68013 烧录方式 及iic生成
硬件程序烧录 1)因为本产品要求将二进制代码和硬件PID/VID烧录在EEPROM,而不是使用CYPRESS推荐的在线下载方式,所以外部采用了8K的EEPROM.上电后68013A会将EEPROM中的 ...
- Qt隐藏标题栏
setWindowFlags (Qt::CustomizeWindowHint)setWindowFlags (Qt::FramelessWindowHint)两个函数都可以去掉标题栏,区别是第一个可 ...
- 关于VS2010error RC2170 : bitmap file res\tmp1.bmp is not in 3.00 format
我们有时候向VS中的程序插入图片,会出现如下错误: 这是VS的一个bug,对于不能识别的资源,添加的时候,VS会弹出一个对话框让你填类型,这个类型其实是字符串表示,而不是像内置类型,例如整数. 解 ...
- QTP与Selenium的比较
1.用户仿真:Selenium在浏览器后台执行,它通过修改HTML的DOM(文档对象模型)来执行操作,实际上是通过javascript来控制的.执行时窗口可以最小化,可以在同一机器执行多个测试.QTP ...
- hadoop之JobTracker功能分析
JobTracker是整个MapReduce计算框架中的主服务,相当于集群的“管理者”,负责整个集群的作业控制和资源管理.本文对JobTracker的启动过程及心跳接收与应答两个主要功能进行分析. 1 ...
- VC6.0打开或者添加工程文件崩溃的解决方法
在Win7操作系统下使用Visual C++ 6.0编程时,如果点击菜单中的[打开]或者[添加],或者按快捷键,都会弹出下图的对话框,出现程序崩溃并退出的情况. 出现这种问题的原因是VC6.0和其他软 ...
- [转载]linux sed命令详解
简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的 ...