C++程序设计——继承

一、继承的概念与定义

1.继承的概念

        继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,这样产生新的类称为派生类。 继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。

2.继承的定义

2.1继承的定义格式

 2.2继承关系和访问限定符

2.3继承基类成员访问方式变化

总结:

(1)基类的private成员在派生类中,无论以什么方式继承都是不可见的,这里所谓的不可见是指基类的私有成员还是被继承到了派生类中,只是语法上限制派生类对象无论在类内部还是类外都不能访问。

(2)基类private成员在派生类中不能被访问,如果基类成员不想在类外直接被访问,但希望在派生类中能被访问,就可以定义为protected。可以看出保护成员限定符是为继承而生。

(3)基类的私有成员在派生类中都是不可见,基类的其他成员在子类的访问方式=min(成员在基类的访问限定符,继承方式),权限范围:public > protected > private。

(4)使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好是显示的写出继承方式。

(5)在实际运用中,一般都是使用public继承,而很少使用protected和private继承,因为protected和private继承下来的成员都只能在派生类的类内部使用,实际中扩展维护性不强。

二、赋值兼容规则

赋值兼容规则(基类和派生类对象赋值转换)的前提:必须是public继承方式

1.派生类可以赋值给基类的对象、基类的指针、基类的引用,反之则不行。

2.基类的指针可以通过强制类型转换赋值给派生类的指针,但是必须是基类的指针是指向派生类对象时,才是安全的。

三、继承中的作用域

1.在继承体系中,基类和派生类都有各自独立的作用域

2.子类和父类有同名的成员时子类成员将屏蔽对父类的同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以通过 基类::基类成员 的方式显示访问

3.对于成员函数的隐藏,只需要函数名相同就构造隐藏;对于成员变量的隐藏,只需要变量名相同就构成隐藏。

4.所以实际中,在继承体系内最好不要定义同名的成员。

四、派生类的默认成员函数

1.派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员,若基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段,显示调用基类的构造函数。

2.派生类的拷贝构造函数必须调用基类的拷贝构造函数,完成基类的拷贝初始化。

3.派生类的赋值运算符重载函数必须调用基类的赋值运算符重载函数,完成基类的赋值。

4.派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。这样才能保证派生类对象先清理派生类成员,再清理基类成员的顺序。

5.派生类对象初始化,先调用基类构造函数,再调用派生类构造函数。(注意:实际实现上是先调用派生类的构造函数,在初始化列表阶段会先调用基类的构造函数,之后才会完成派生类部分成员的初始化)

6.派生类对象销毁,先调用派生类析构函数,再调用基类析构函数。

五、继承与友元

        友元关系不能继承,也就是说基类的友元不能访问子类的私有成员和保护成员。

六、继承与静态成员

        基类定义的static静态成员,在整个继承体系里面只有一个这样的成员。也就是说,无论派生出多少个实例,都只有这一个static成员实例。

七、菱形继承和菱形虚拟继承

1.单继承

        一个子类只有一个直接父类。

2.多继承

        一个子类有两个或以上的直接父类。

3.菱形继承 

3.1菱形继承

        菱形继承是多继承的一种特殊情况。

3.2菱形继承的问题

        根据对象成员的构造模型,可以看出菱形继承有数据冗余二义性问题。因为在cat的对象中,Creature成员会存在两份。

3.3解决方法

(1)访问明确化——二义性问题

        当访问最顶层成员时(Creature成员),加上其父类名称(Animal::成员 或 Pet::成员)。

(2)菱形虚拟继承

        让最顶层基类的成员,在该类对象(cat类)中只存储一份。解决二义性和数据冗余问题。

4.菱形虚拟继承

虚拟继承:virtual关键字修饰继承关系

        当多个类通过虚拟继承的方式继承同一个类时,对于继承自父类的成员是共有的,所以为了方便处理,在内存中分布的时候,会将这些共有的成员放到对象组成的末尾。

        然后建立一个虚基表,来记录各个虚拟继承类在访问共有成员时,在内存中的偏移量大小,虚基表指针就是指向了各自的偏移量。

注意:

(1)虚拟继承主要用来实现菱形虚拟继承,目的是解决菱形继承中的二义性和数据冗余,不要在其他地方使用。

(2)注意菱形虚拟继承中,虚拟继承的位置是中间,最底层采用虚拟继承没有作用。

八、继承与组合

(1)public继承是一种is-a的关系,相当于每个派生类对象都是一个基类对象。

(2)组合是一种has-a的关系,比如A组合了B,那么每个A对象中,都有一个B对象。

(3)继承允许根据基类的实现来定义派生类的实现。这种通过派生类的方式实现复用通常被称为白箱复用。 所谓“白箱”是相对可视性而言,在继承方式中,基类的内部实现对派生类可见。所以继承一定程度的破坏了基类的封装性,且基类的改变对派生类影响很大,派生类对基类有较强的依赖关系,耦合度高。

(4)对象组合是类继承以外的另一种复用方式。新的或更复杂的功能,可以通过组合对象来实现。对象组合要求被组合的对象具有良好定义的接口。这种复用方式称为黑箱复用,因为对象的内部实现不可见。对象只以“黑箱”的形式出现,组合类之间没有很强的依赖关系,耦合度低,优先使用组合,有助于维护类的封装性。

优先使用组合:

(1)可以的情况下优先使用组合。

(2)对于更适合继承关系的情况,才选择使用继承。

(3)要实现多态时,必须使用继承。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
《现代C++程序设计(原书第2版)》图文并茂,通俗易懂,真正做到寓教于乐,是一本难得的C++面向对象设计入门教材。 出版者的话 译者序 前言 第1章 C++概述与软件开发 1.1 什么是C语言和C++ 1.1.1 C和C++历史回顾 1.1.2 C/C++是一门编译语言 1.1.3 为什么许多程序员都选择C++ 1.2 什么是面向对象 1.2.1 C++程序并不一定是面向对象的 1.2.2 一个简单的面向对象程序示例 1.2.3 面向对象的软件更有优势 1.3 结构化设计与面向对象设计 1.3.1 ATM——结构化设计 1.3.2 采用面向对象方法的ATM——究竟是谁的任务 1.3.3 汽车维护——结构化设计 1.3.4 采用面向对象方法的汽车维护——究竟是谁的任务 1.4 软件开发技术概述 1.5 问题发现与解决 复习题 第2章 C++的入门知识 2.1 编程基础 2.1.1 算法设计 2.1.2 正确的软件开发步骤 2.2 专业术语及工程创建 2.3 C++程序的一般格式 2.3.1 “Hello World!”程序 2.3.2 “How’s the Weather?”程序 2.4 程序的数据及数据类型 2.4.1 C++的数据类型 2.4.2 容器=数据类型,标签=变量名 2.4.3 数据类型修饰符 2.4.4 问题分析:整型数据究竟有多大 2.5 C++中的变量声明 2.5.1 C++的命名规则 2.5.2 在哪里声明变量 2.6 C++中的运算符 2.6.1 计算路程的程序 2.6.2 从键盘输入程序所需数据 2.6.3 赋值运算符 2.6.4 运算符的优先级 2.6.5 数据类型及其存储的值 2.6.6 算术运算符 2.6.7 自增运算符和自减运算符 2.6.8 复合赋值运算符 2.7 #define、const和数据类型转换 2.7.1 #define预处理指令 2.7.2 const修饰符 2.7.3 const比#define好吗 2.7.4 数据类型转换 2.8 关于键盘输入和屏幕输出的更多内容 2.8.1 转义序列 2.8.2 ios格式标记 2.8.3 流的IO控制符 2.9 开始使用类和对象、C++string类 2.10 练习 复习题 第3章 控制语句和循环 3.1 关系运算符和逻辑运算符 3.2 if语句 3.2.1 if-else语句 3.2.2 问题分析:在if语句中使用大括号 3.2.3 if-else if-else语句 3.2.4 低效的编程方法 3.2.5 if-else程序示例 3.2.6 嵌套if-else语句 3.2.7 条件运算符“?” 3.3 switch语句 3.4 循环 3.4.1 括号的用法 3.4.2 无限循环 3.5 for循环 3.5.1 不要改变循环索引 3.5.2 for循环示例 3.6 while循环 3.7 do while循环 3.8 跳转语句 3.8.1 break语句 3.8.2 continue语句 3.9 问题发现与解决 3.9.1 五个常见错误 3.9.2 调试程序 3.10 C++类与vector类 3.11 总结 3.12 练习 复习题 第4章 函数一:基础 4.1 C++中的函数 4.1.1 只由一个main函数构成的程序 4.1.2 包含多个函数的程序 4.1.3 函数是个好东西 4.1.4 三个重要的问题 4.2 函数:基本格式 4.3 函数的编写要求 4.3.1 你想住在C++旅馆中吗 4.3.2 函数为先 4.3.3 函数声明或函数原型 4.3.4 函数定义、函数标题行与函数体 4.3.5 函数调用 4.3.6 传值调用 4.3.7 问题分析:未声明的标识符 4.4 重载函数 4.5 具有默认输入参数列表的函数 4.6 局部变量、全局变量和静态变量 4.6.1 局部变量 4.6.2 块范围 4.6.3 全局变量 4.6.4 危险的全局变量 4.6.5 问题分析:全局变量y0、y1与cmath 4.6.6 静态变量 4.7 C++stringstream类 4.8 总结 4.9 练习 复习题 第5章 函数二:变量地址、指针以及引用 5.1 数据变量和内存 5.1.1 sizeof运算符 5.1.2 预留内存 5.1.3 计算机内存和十六进制 5.2 取地址运算符& 5.3 指针 5.4 函数、指针以及间接运算符 5.4.1 解决思路 5.4.2 指针和函数 5.4.3 有效处理大型数据 5.5 函数和引用 5.5.1 复习:两种机制 5.5.2 为什么要强调指针的重要性 5.6 queue类 5.7 总结 5.8 练习 复习题 第6章 数组 6.1 使用单个数据变量 6.2 数组基础 6.2.1 数组的索引值从0开始 6.2.2 使用for循环和数组来实现的电话账单程序 6.2.3 数组的声明和初始化 6.2.4 数组越界==严重的问题 6.2.5 vector与数组的比较 6.3 数组和函数 6.3.1 每个数组都有一个指针 6.3.2 数组指针 6.3.3 向函数传递数组:最开始的引用调用 6.3.4 利用数组和函数生成随机数并进行排序 6.4 C字符串,也称为字符数组 6.4.1 字符数组的初始化 6.4.2 null字符 6.4.3 C字符串的输入 6.4.4 C++中提供的字符数组函数 6.5 多维数组 6.5.1 二维数组的初始化 6.5.2 嵌套的for循环和二维数组 6.5.3 利用二维数组来实现Bingo游戏 6.6 多维数组和函数 6.6.1 改进的Bingo卡片程序 6.6.2 白雪公主:利用二维数组来存储姓名 6.7 利用数据文件对数组赋值 6.8 总结 6.9 练习 复习题 第7章 类和对象 7.1 我们所了解的类和对象 7.2 编写自己的类 7.2.1 入门实例:自定义日期类 7.2.2 第一个C++类:Date类 7.2.3 揭开类的生命之谜 7.2.4 set和get函数的作用与VolumeCalc类 7.2.5 PICalculator类 7.3 作为类成员的对象 7.4 类的析构函数 7.5 对象数组 7.6 重载运算符与对象 7.7 指针、引用和类 7.7.1 指针和引用实例 7.7.2 处理日期和时间的程序实例 7.8 总结 7.9 练习 复习题 第8章 继承和虚函数 8.1 为什么继承如此重要 8.1.1 IceCreamDialog实例 8.1.2 Counter类实例 8.2 继承基础 8.2.1 Counter和DeluxeCounter实例 8.2.2 保护成员 8.2.3 员工、老板和CEO 8.3 访问控制符的规范和多继承 8.4 继承、构造和析构 8.4.1 构造函数和析构函数回顾 8.4.2 基类和派生类的默认构造函数——没有参数 8.4.3 在重载的构造函数中使用参数 8.4.4 基类和派生类的析构函数 8.4.5 医生也是人 8.4.6 关于派生类和基类构造函数的规则 8.5 多态和虚函数 8.5.1 多态——同一个接口,不同的行为 8.5.2 什么是虚函数 8.5.3 虚函数的作用 8.6 总结 8.7 练习 复习题 附录A 学习使用Visual C++2005Express Edition 附录B C++关键字表 附录C C++运算符 附录D ASCII码 附录E 位、字节、内存和十六进制表示 附录F 文件输入/输出 附录G 部分C++类 附录H 多文件程序 附录I Microsoft visual C++2005Express Edit
用c++/qt写的项目,可供自己学习,项目都经测试过,真实可靠,请放心使用。Qt支持 Windows、Linux/Unix、Mac OS X、Android、BlackBerry、QNX等多种平台,并为这些不同的平台提供了统一的开发环境。 面向对象 C++是完全面向对象的,这一点和Objective-c等在开发很相似。而Qt又是基于C++一种语言的扩展,大家都知道C++ 有快速、简易、面向对象等很多优点,所以Qt自然也继承者C++这些的优点。 Qt良好的封装机制使得Qt的模块化程度非常高,可重用性较好,对用户开发来货是非常方便的。Qt提供一种为signals/slots(信号和槽) 的安全类型来替代callback,使得各个元件之间的协同工作变得十分简单。 丰富的API Qt包括多达 250 个以上的 C++ 类,还提供基于模板的 collections, serialization, file, I/Odevice, directory management, date/time 类。甚至还包括正则表达式的处理功能。 支持 2D/3D 图形渲染,支持 OpenGL。 大量的开发文档。 XML支持 Webkit 引擎的集成,可以实现本地界面与Web内容的无缝集成, 但是真正使得 Qt 在自由软件界的众多 Widgets (如 Lesstif,Gtk,EZWGL,Xforms,fltk 等等)中脱颖而出的还是基于 Qt 的重量级软件 KDE。 信号和槽机制 Qt提供了信号和槽机制用于完成见面操作的响应,是完成任意两个Qt对象之通信机制。其中,信号会在某个特定情况或动作下被触动,槽是等同于接受并处理信号的函数。 为什么方法不是直接调用的。中间用到 Signal 和槽机制不是多此一举? 其实在我们生活也是一样,老板级别的好说话,老板给助理分派任务也好说话,但是助理给老板分任务,可想而知会有什么后果,在以前的统治阶层肯定不允许这样的事发生。所以在分层思想中,我们所调用的函数也是这样的,上层可以调用下层和同一层的函数,下层函数不可以调用上层函数,否则程序的层次性会被打破,导致结构错综复杂,难以维护和管理。 那么怎样才能做到向上管理呢,有任务分配给老板怎么办? 老板会设立一个机构,也就是一个函数,用无限循环来查询助理的状态,如果助理真的有事情,这个机构就把这消息拿到老板来处理。但是这种处理方式显得有些复杂,我们想要的简单明了的方式是,如果助理有事件发生,可以直接调用老板函数处理。 说了这么多其实就是想说,信号和槽的最大优势在于,它完善了程序分层的思想,可以在不改变程序的层次性的情况下,完成由下层到上层的调用。在下层发出一个 Signal,这时上层与其想关联的 Slot 函数就会响应。
好的,我会尽力回答你的问题。首先,我们来设计一个 Student 学生类,包括以下属性: - 学号(id) - 姓名(name) - 年龄(age) - 性别(gender) - 成绩(score) 首先,我们可以定义一个 Student 类,如下所示: ```cpp class Student { public: int id; string name; int age; string gender; double score; }; ``` 接下来,我们可以通过继承来创建一个更具体的类,比如说 Undergraduate 本科生类。我们可以从 Student 类中继承属性,并添加一些新的属性和方法,如下所示: ```cpp class Undergraduate : public Student { public: string major; int year; void display() { cout << "ID: " << id << endl; cout << "Name: " << name << endl; cout << "Age: " << age << endl; cout << "Gender: " << gender << endl; cout << "Score: " << score << endl; cout << "Major: " << major << endl; cout << "Year: " << year << endl; } }; ``` 在这个例子中,我们使用了 public 继承,使得 Undergraduate 类可以访问 Student 类中的公有成员。我们还定义了一个新的方法 display,用于打印出 Undergraduate 类中的所有属性。 最后,我们可以通过重写父类的方法来定制化 Undergraduate 类的行为。比如说,我们可以重写 Student 类中的 display 方法,如下所示: ```cpp class Undergraduate : public Student { public: string major; int year; void display() { cout << "ID: " << id << endl; cout << "Name: " << name << endl; cout << "Age: " << age << endl; cout << "Gender: " << gender << endl; cout << "Score: " << score << endl; cout << "Major: " << major << endl; cout << "Year: " << year << endl; cout << "This is an undergraduate student." << endl; } }; ``` 在这个例子中,我们重写了 display 方法,添加了一行文本,用于提示这是一个本科生对象。 希望这个例子能够帮助你理解 C++ 中的类设计继承和重写。如果你有任何其他问题,可以随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hey小孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值