[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: 修饰的成员变量方法,在类的内部使用 ,在继承的子类中可用 ...
随机推荐
- JSAPI_Ticket签名
1.微信 JS 接口签名校验工具 2.具体开发 2.1 获取access_token,然后jsapi_ticket /** * 获取access_token,然后jsapi_ticket */ pri ...
- Lex+YACC详解
1. 简介 只要你在Unix环境中写过程序,你必定会邂逅神秘的Lex&YACC,就如GNU/Linux用户所熟知的Flex&Bison,这里的Flex就是由Vern Paxon实现的一 ...
- Redbean:入门(三) - Exec 以及 Query 以及 ConvertToBeans
<?php //引入rb入口文件 include_once 'rb.php'; //定义dsn以及相关的数据 $dsn = 'mysql:host=localhost;dbname=hwibs_ ...
- JavaScript高级程序设计之location对象
location对象用来处理URL的相关信息 1.获取查询字符串 // 获取查询字符串对象 var getQueryStringArgs = function () { ? location.sear ...
- golang与C交互:cgo
1. 在Go中引用C代码很简单, 在 import "C"前用注释引入标准的C代码, 然后使用C.xxx的伪包引用C代码空间的标识符即可. 需要注意, import"C& ...
- Spring Roo
Spring Roo 是SpringSource新的开放源码技术,该技术主要面向企业中的Java开发者,使之更富有成效和愉快的进行开发工作,而不会牺牲工程完整或灵活性.无论你是一个新的Java开发人员 ...
- php捕获网络页面
<?php $url = 'http://jwzx.cqupt.edu.cn/pubYxKebiao.php?type=zy&yx=06'; $html = file_get_conte ...
- 55.ERROR:Place:1136 - This design contains a global buffer instance…… non-clock load pins off chip
ISE在布局布线时,出现下图所示错误. 对于"clock_dedicated_route”错误原因有两种情况: 1. 就是有一个时钟你没有放到全局时钟或者局部时钟的引脚,布局的时候不能把它 ...
- 使用C语言在Win控制台中实现指定位置输出
在古老的Turbo C中有个GotoXY可以让你在指定坐标中输出文字,可恨的是我看过的C语言书籍,有一半都是关于它的.我现在用着Windows系统,不可能还让我去写着DOS程序啊,起码也得从Win控制 ...
- Spring MVC常用的注解类
一.注解类配置 要使用springmvc的注解类,需要在springmvc.xml配置文件中用context:component-scan/扫描:  二.五大重要的注解类 1.RequestMapp ...