[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: 修饰的成员变量方法,在类的内部使用 ,在继承的子类中可用 ...
随机推荐
- java遍历Map的几种方式
1.遍历map的几种方式:private Hashtable<String, String> emails = new Hashtable<String, String>(); ...
- myeclipse激活+Aptana安装配置
一.Myeclipse安装激活. 安装过程一路向下. 1.破解公钥,确保MyEclipse没有开启,否则失败! 用WinRAR或7-zip打开安装目录下Common\plugins\com.genui ...
- hdu 1303 Doubles
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1303 Doubles Description As part of an arithmetic com ...
- core java 7 exception
MODULE 7 Exceptions---------------------------- 程序正常执行过程中遇到的意外情况 引发异常的因素: 1)程序本身的内在因素 2)外部因素引发的,程序无须 ...
- 在.net程序中使用System.Net.Mail来发送邮件
System.Net.Mail是微软自家提供的工具,在.net程序中可以使用该空间中的SmtpClient实例来实现邮件的发送. 使用System.Net.Mail空间与Web.config配置相配合 ...
- 009--VS2013 C++ 显示位图部分透明化
其实这个更简单,只是把上一编文章的半透明化的代码去掉就可以啦 还是原来那张图片: //全局变量HBITMAP bg, girl;HDC mdc;//起始坐标const int xstart = 50; ...
- 设置xx-net,访问youtube等国外网站
配合使用chrome+xx-net,就可以免费访问youtube等外网了.步骤如下: 1. 按照https://github.com/XX-net/XX-Net/wiki/%E4%BD%BF%E7%9 ...
- Linux C 文件与目录3 文件读写
文件读写 文件读写是指从文件中读出信息或将信息写入到文件中.Linux文件读取可使用read函数来实现的,文件写入可使用write函数来实现.在进行文件写入的操作时,只是在文件的缓冲区中操作,可能没有 ...
- activemq整合spring
- 二叉查找树(BST)
二叉查找树(BST):使用中序遍历可以得到一个有序的序列