C++面向对象程序设计学习笔记(5)
派生类与继承
概念
继承允许编程者在已有类的基础上创建新的类,可以从一个或者多个已有类中继承函数和数据,并重新定义或者添加新的函数和数据,已有类称为基类或父类,新类称为派生类和子类。
声明
声明一个派生类的一般格式为:
class 派生类名 : [继承方式] 基类名
{
派生类新增的数据成员和成员函数
};
继承方式种类有 private, public ,protected ,分别为私有、公有和保护继承
若不显式地给出关键字,则默认为私有
构成
构造一个派生类包括三部分公作:
1)派生类从基类接受成员
派生类将基类除构造函数和析构函数以外的全部成员全部接收
2)调整从基类接收来的成员
调整包括两个方面 改变基类成员在派生类中的访问属性(通过继承方式实现)
对基类成员重定义(派生类的同名成员会覆盖基类中的同名成员)
3)在派生类中添加新的成员
基类成员在派生类中的访问属性
基类中的成员 | 在公有派生类中的访问属性 | 在私有派生类中的访问属性 | 在保护派生类中的访问属性 |
---|---|---|---|
私有成员 | 不可直接访问 | 不可直接访问 | 不可直接访问 |
公有成员 | 公有 | 私有 | 保护 |
保护成员 | 保护 | 私有 | 保护 |
派生类对基类成员的访问规则
派生类对基类成员的访问形式主要有两种:
(1)内部访问 由派生类中新增的成员函数对基类继承来的成员的访问
(2)对象访问 在派生类外部,通过派生类对象对从基类继承来的成员的访问
私有继承的访问规则
基类中的成员 | 私有成员 | 公有成员 | 保护成员 | |
---|---|---|---|---|
访问方式 | 内部访问 | 不可访问 | 可访问 | 可访问 |
对象访问 | 不可访问 | 不可访问 | 不可访问 |
公有继承的访问规则
基类中的成员 | 私有成员 | 公有成员 | 保护成员 | |
---|---|---|---|---|
访问方式 | 内部访问 | 不可访问 | 可访问 | 可访问 |
对象访问 | 不可访问 | 可访问 | 不可访问 |
保护继承的访问规则
基类中的成员 | 私有成员 | 公有成员 | 保护成员 | |
---|---|---|---|---|
访问方式 | 内部访问 | 不可访问 | 可访问 | 可访问 |
对象访问 | 不可访问 | 不可访问 | 不可访问 |
派生类的构造函数和析构函数
基类的构造函数和析构函数不能被继承,所有从派生类的初始化需要加入派生类的构造函数,而基类继承下来的成员的初始化还是有基类的构造函数完成的,析构函数同理。
执行顺序
创建派生类对象时,先执行基类构造函数,再执行派生类的构造函数,
在撤销派生类对象时,先执行派生类析构函数,再执行基类的析构函数。
构造规则
简单派生类的构造函数
派生类构造函数的一般格式为
派生类名(参数总表):基类名(参数表)
{
派生类新增数据成员的初始化语句
}
基类构造函数的参数通常来自于派生类构造函数的参数总表,也可以用常数值
若基类使用默认构造函数或不带参数的构造函数,则可略去基类的构造函数,若此时不需要构造函数,则可不定义派生类构造参数
当基类构造函数中存在参数,则派生类必须定义构造函数
含有对象成员的派生类的构造函数
构造参数的一般形式为
派生类名(参数总表):基类名(参数表0),对象成员名1(参数表 1),......,对象成员名n(参数表 n)
{
派生类新增数据成员的初始化语句
}
该构造函数执行顺序如下:
+调用基类的构造函数;
+调用内嵌对象成员的构造函数;
+执行派生类的构造函数体;
注意:
1.当派生类中含有多个内嵌对象成员时,调用内嵌对象成员的构造函数顺序由它们在类中的声明顺序决定
2.若派生类的基类也是派生类,则每个派生类只需负责其直接基类数据成员的初始化
调整基类成员在派生类中的访问属性的其他方法
同名成员
派生类可以重新说明与基类成员同名的成员,在派生类使用该名字意味着访问在派生类中重新定义的成员,若要访问基类的同名成员,则需要在该成员名前加上基类名和作用域标识符"::"
例:
class X
{
public:
X();
~X();
void f();
};
class Y:public X
{
public:
Y();
~Y();
void f();
};
//若要访问派生类中的f(),则调用函数f()或Y::f()
//若要访问基类中的f(),则调用函数X::f()
访问声明
对于私有继承,外界无法利用派生类的对象直接调用基类的成员函数,只能通过调用派生类的成员函数间接调用基类的成员函数
C++提供类称为访问声明的特殊机制,可以个别调整基类中的某些成员,使之在派生类中保持原有的访问属性
访问声明的方法就是把基类的保护或公有成员直接写至私有派生类定义式中的同名段中,同时冠以基类名和作用域标识符"::",利用这种方法该成员即成为派生类的保护和公有成员
例
class X:private Y
{
public:
X();
~X();
A::print;
};
注意:
1.数据成语也可以使用访问声明
2.访问声明中只含不带类型和参数的函数名和变量名
3.访问声明不能改变成员在基类中的访问属性
4.对于基类中的重载函数名,访问声明将对基类中的所有同名函数起作用
多重继承
当一个派生类具有两个或多个基类时,即称为多重继承或多基继承。
多重继承派生类的声明
声明一般形式如下
class 派生类名 : 继承方式1 基类1 ,......,继承方式n 基类n
{
派生类新增的数据成员和成员函数
}
继承方式即:private,pubilc,protected,默认继承方式为 private
注意:对基类成员的访问必须是无二义的
多重继承派生类的构造函数和析构函数
多重继承派生类的构造函数的一般形式如下:
派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),......,基类名n(参数表n)
{
派生类新增成员的初始化语句
}
多重继承派生类的构造函数与单继承下派生类构造函数相似,它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数
多重继承派生类的构造函数与单继承下派生类构造函数的执行顺序相同,也是遵循先执行基类的构造函数,再执行对象成员的构造函数,最后执行派生类的构造函数体的原则。
析构函数与单继承的情况类似
虚基类
虚基类的意义:避免产生二义性
虚基类的概念
在c++中,如果想使这个公共的基类只产生一个复制,则可以将这个基类说明为虚基类。
虚基类在派生类中声明,其语法形式如下:
class 派生类名:virtual 继承方式 基类名
{
......
}
虚基类的初始化
虚基类的初始化与一般的多继承的初始化在语法上是一样的,但构造函数的调用顺序不同。
注意:
1.如果在虚基类中定义带有形参的构造函数,并且没有定义默认形式的构造参数,则整个继承结构中,所有直接或间接的派生类都必须在构造函数的成员初始化列表中列出对虚基类构造函数的调用。
2.建立一个对象时,如果这个对象中含有从虚基类继承来的成员,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。
3.若同一个层次中同时包含虚基类和非虚基类,应先调用虚基类的构造函数,再调用非虚基类的构造函数,最后调用派生类构造函数。
4.虚基类不影响构造函数的调用顺序。
说明:
1.关键字virtual和派生方式关键字(public 或 private)的先后顺序无关紧要。
2.一个基类既可以作为某些派生类虚基类,也可以作为另一些派生类的非虚基类。
基类与派生类对象之间的赋值兼容关系
在一定条件下,不同类型的数据之间可以进行类型转换,这种不同类型数据之间的自动转换和赋值称为赋值兼容
在基类与派生类对象之间的赋值兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代
在基类对象可以使用的任何地方,都可以使用派生类的对象来替代,但只能使用从基类继承来的成员,具体表现在以下几个方面。
1.派生类对象可以向基类对象赋值
2.派生类对象可以初始化基类对象的引用
3.派生类对象的地址可以赋给指向基类对象的指针
4.如果函数的形参是基类对象或基类对象的引用,在调用函数时可以用派生类对象作为实参
说明:
1.声明为指向基类对象的指针可以指向它的公有派生的对象,但不允许指向它的私有派生的对象
2.允许将一个声明为指向基类的指针指向其公有派生类的对象,但是不能将一个声明为指向派生类对象的指针指向其基类的一个对象
C++面向对象程序设计学习笔记(5)的更多相关文章
- C++面向对象程序设计学习笔记(1)
基本概念 对象: 面向对象程序设计中,对象是描述其属性的数据以及对这些数据施加的一组操作封装在一起构成的统一体,每个对象都是由数据和操作代码两部分构成的. 类: 面向对象程序设计中,类是具有相同的数据 ...
- C++面向对象程序设计学习笔记(6)
多态性 编译时的多态性与运行时的多态性 在面向对象方法中,所谓多态性就是不同对象收到相同信息时,产生不同的行为.在c++程序设计中,即"一个接口,多种方法" 在C++中,多态性的实 ...
- C++面向对象程序设计学习笔记(7)
模板与异常处理 模板的概念 模板是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型作为参数. 模板分为函数模板和类模板,它们分别允许用户构造模板类和模板函数 函数模板与模板函数 函数模板实际 ...
- C++面向对象程序设计学习笔记(4)
类与对象(2) string类 C++不仅向下兼容C的字符表示方法,也声明了一种更方便的字符串类型,即string类. 想要使用string类,必须包括头文件string,即要声明 #include& ...
- C++面向对象程序设计学习笔记(3)
类与对象(1) 结构体与类 结构体的扩充 C++对结构体进行了扩充,它不仅可以含有不同类型的数据,还可以含有函数,结构体的函数可以像访问结构体中的数据一样进行访问. 类的声明 声明类的方法与声明结构体 ...
- C++面向对象程序设计学习笔记(2)
C++在非面向对象方面的扩充 C++向下兼容C语言,因此C语言中的语法在C++中依然成立 输入输出 C++添加了标准输入流对象cin和标准输出流对象cout来进行输入输出, 例: #include&l ...
- 20145213《Java程序设计学习笔记》第六周学习总结
20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...
- Java程序设计学习笔记(一)
时间:2015-6-2 23:04 程序员,程序猿,程序媛,码农 ------------------------------------------------------- --Java的应用 ...
- JavaScript高级程序设计---学习笔记(二)
面向对象程序设计1.属性类型.定义多属性.读取属性特性对象的属性在创建时都带有一些特征值,JavaScript通过这些特征值来定义它们的行为.这些特性是为了实现JavaScript引擎用的,因此不能直 ...
随机推荐
- c++类的学习笔记
用结构体数据的安全性得不到保证. 使用类对数据进行封装,只能通过函数修改类中的数据 (1)类的定义 class 类名 { private: protected: public: }; private: ...
- Ubuntu命令行打开新终端并执行脚本
gnome-terminal -x bash -c "bash test.sh;exec bash;"
- [探究] dsu on tree,一类树上离线问题的做法
dsu on tree. \(\rm 0x01\) 前言\(\&\)技术分析 \(\bold{dsu~on~tree}\),中文别称"树上启发式合并"(虽然我并不承认这种称 ...
- 【cf比赛记录】Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4)
比赛传送门 只能说当晚状态不佳吧,有点头疼感冒的症状.也跟脑子没转过来有关系,A题最后一步爆搜没能立即想出来,B题搜索没有用好STL,C题也因为前面两题弄崩了心态,最后,果然掉分了. A:简单数学 B ...
- 剑指offer:矩阵中的路径(递归回溯法DFS类似迷宫)
1. 题目描述 /* 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径. 路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子. 如果一条 ...
- 洛谷 P1840 【Color the Axis_NOI导刊2011提高(05)】 题解
看了一下题解,显然在做无用功啊,而且麻烦了许多,但是这道题真心不难,显然是一个区间修改的题目,然后查询的题目 我的线段树只需要记录一个量:区间和 看了一下其他题解的pushdown函数,发现真心写的很 ...
- JavaScript对象及初识面向对象
一.对象 1.1对象是什么 对象是包含相关属性和方法的集合体 1.2什么是面向对象 面向对象仅仅是一个概念或者编程思想 通过一种叫做原型的方式来实现面向对象编程 二.创建对象 2.1自定义对象 2.1 ...
- 自动化API之一 自动生成Mysql数据库的微服务API
本文演示如何利用Uniconnector平台,自动生成Mysql数据库的API,节约开发人员编写后台API的时间.使用生成API的前提是开发者有 自己的数据库,有数据库的管理权限,并能通过外网 ...
- C语言中的scanf与scanf_s 以及循环输入的问题解决
Scanf 在标准C中,scanf提供了键盘输入功能. scanf函数是一个标准库函数,它的函数原型在头文件“stdio.h”中.与printf函数相同,C语言也允许在使用scanf函数之前不必包含s ...
- 使用 jQuery.AutoComplete 让文本框自动完成
直接贴代码了. @section headSection { <script type="text/javascript"> $(document).ready(fun ...