派生类与继承

概念

继承允许编程者在已有类的基础上创建新的类,可以从一个或者多个已有类中继承函数和数据,并重新定义或者添加新的函数和数据,已有类称为基类或父类,新类称为派生类和子类。

声明

声明一个派生类的一般格式为:

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)的更多相关文章

  1. C++面向对象程序设计学习笔记(1)

    基本概念 对象: 面向对象程序设计中,对象是描述其属性的数据以及对这些数据施加的一组操作封装在一起构成的统一体,每个对象都是由数据和操作代码两部分构成的. 类: 面向对象程序设计中,类是具有相同的数据 ...

  2. C++面向对象程序设计学习笔记(6)

    多态性 编译时的多态性与运行时的多态性 在面向对象方法中,所谓多态性就是不同对象收到相同信息时,产生不同的行为.在c++程序设计中,即"一个接口,多种方法" 在C++中,多态性的实 ...

  3. C++面向对象程序设计学习笔记(7)

    模板与异常处理 模板的概念 模板是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型作为参数. 模板分为函数模板和类模板,它们分别允许用户构造模板类和模板函数 函数模板与模板函数 函数模板实际 ...

  4. C++面向对象程序设计学习笔记(4)

    类与对象(2) string类 C++不仅向下兼容C的字符表示方法,也声明了一种更方便的字符串类型,即string类. 想要使用string类,必须包括头文件string,即要声明 #include& ...

  5. C++面向对象程序设计学习笔记(3)

    类与对象(1) 结构体与类 结构体的扩充 C++对结构体进行了扩充,它不仅可以含有不同类型的数据,还可以含有函数,结构体的函数可以像访问结构体中的数据一样进行访问. 类的声明 声明类的方法与声明结构体 ...

  6. C++面向对象程序设计学习笔记(2)

    C++在非面向对象方面的扩充 C++向下兼容C语言,因此C语言中的语法在C++中依然成立 输入输出 C++添加了标准输入流对象cin和标准输出流对象cout来进行输入输出, 例: #include&l ...

  7. 20145213《Java程序设计学习笔记》第六周学习总结

    20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...

  8. Java程序设计学习笔记(一)

    时间:2015-6-2 23:04 程序员,程序猿,程序媛,码农 -------------------------------------------------------   --Java的应用 ...

  9. JavaScript高级程序设计---学习笔记(二)

    面向对象程序设计1.属性类型.定义多属性.读取属性特性对象的属性在创建时都带有一些特征值,JavaScript通过这些特征值来定义它们的行为.这些特性是为了实现JavaScript引擎用的,因此不能直 ...

随机推荐

  1. Asp.Net Core AsyncLocal 异步上下文

    引子 阅读以下代码,并尝试分析 代码解析 在主线程中,线程Id为1,为线程变量赋值 变量==d6ff 开启一个新的task,此时线程Id为4,变量==d6ff,并调用Task1 开启一个同步Task3 ...

  2. C#教程之C#属性(Attribute)用法实例解析

    引用:https://www.xin3721.com/ArticlecSharp/c11686.html 属性(Attribute)是C#程序设计中非常重要的一个技术,应用范围广泛,用法灵活多变.本文 ...

  3. redis之主从同步

    很多企业都没有使用到 Redis 的集群,但是至少都做了主从.有了主从,当 master 挂掉的时候,运维让从库过来接管,服务就可以继续,否则 master 需要经过数据恢复和重启的过程,这就可能会拖 ...

  4. hdu-5573 Binary Tree

    The Old Frog King lives on the root of an infinite tree. According to the law, each node should conn ...

  5. 【转】EF架构~为EF DbContext生成的实体添加注释(T5模板应用)

    嗨,没法说,EF4的TT模版加上注释后,升级到EF5的TT模版后,注释就不通用了,所以,还得再研究一下,然后把操作方法再分享出来,没辙的微软! T4模版可能有些凌乱,这在T5模版里有了不错的改进,但我 ...

  6. 异步IO/协程/数据库/队列/缓存(转)

    原文:Python之路,Day9 - 异步IO\数据库\队列\缓存 作者:金角大王Alex add by zhj: 文章很长 引子 到目前为止,我们已经学了网络并发编程的2个套路, 多进程,多线程,这 ...

  7. DVWA-CSRF学习笔记

    DVWA-CSRF学习笔记 一.CSRF(跨站请求伪造) CSRF(跨站请求伪造),是指利用受害者尚未失效的身份认证信息(cookie.session会话等),诱骗其点击恶意链接或者访问包含攻击代码的 ...

  8. SQL Server备份时间段内插入的数据依旧进入了备份文件?(转载)

    问 MSSql我在本机测试了下.为了延长备份时间,找个大的数据库.开始完整备份bak然后再此库新建表,并增添数据.备份结束.==================还原备份后,在还原的数据库内发现新增的表 ...

  9. 分布式Redis深度历险-Sentinel

    上一篇介绍了Redis的主从服务器之间是如何同步数据的.试想下,在一主一从或一主多从的结构下,如果主服务器挂了,整个集群就不可用了,单点问题并没有解决.Redis使用Sentinel解决该问题,保障集 ...

  10. java基本程序设计结构总结

    学习一门语言:(1)掌握它的表现形式(2)这些语言什么应用. 1.1关键字 1.关键字是被赋予了特殊含义的单词. 2.关键字特点:关键字所有字母都小写. 3.类名的每一个单词开头必须大写. 1.2标识 ...