c++面向对象的程序设计

1.面向对象的程序设计的核心思想是数据抽象、动态绑定和继承。

继承:根部称作基类,继承得来的类称作派生类。派生类必须通过使用派生类列表来明确指出它是从哪个基类继承而来的,列表形式是一个冒号,后面紧跟逗号分隔的基类列表。基类可将函数声明成虚函数来让派生类定义自己的版本。

动态绑定:动态绑定指的是在运行时才知道函数的运行版本,因此我们在使用基类的引用(或指针)调用一个虚函数时会发生动态绑定。

2.定义基类和派生类

a.基类通常该定义一个虚析构函数;

b.成员函数如果没被声明为虚函数,其解析过程发生在编译时而非运行时。

c.派生类和其他类一样能访问基类公有成员,不能访问私有成员。但是派生类能访问受保护(protected)成员,其他类不行。

d.类派生列表的基类可以使用访问说明符:public、protected或者private

e.一个派生类对象包含多个部分:一个含有派生类自己定义的成员,一个派生类继承基类对应的子对象。自己理解:只需一个派生类对象,在需要时可转化为基类的引用

f.派生类对象中从基类继承过来的成员不能使用派生类的构造函数初始化,必须使用基类的构造函数初始化。

g.派生类的声明包含类名但是不包含它的派生列表。

h.如果想将某个类用作基类,就必须定义而非仅仅声明,防止继承用关键词final。

i.不存在从基类向派生类的隐式转换,对象之间不存在类型转换。因此派生类对象的引用向基类转换时,调用的是基类的构造函数,也就只能调用基类的成员。派生类的成员就被忽略掉了。

3.虚函数

a.引用或指针的静态类型与动态类型不同这一事实是c++语言支持多态性的根本所在。

b.新标准中可以使用override关键字来说明派生类中的虚函数。

C.

一个函数在基类中被声明为虚函数,那么在派生类override覆盖基类的这个函数时可以不加virtual关键字,因为一个函数一旦被声明为虚函数时,那么它在所有派生类中也是虚函数。

一个派生类的函数如果覆盖了基类的虚函数,那么这个函数的参数和返回类型必须和虚函数一致。

自己测试了下,当派生类覆盖基类的函数形参或者返回类型与基类的虚函数不一致时,这个函数被编译器认为是派生类重新自己定义的新的函数,而不被认为是覆盖掉基类的虚函数。如果我们在实际变成中发生这种错误是很难发现的,我在测试时是在派生类的函数中添加了override关键字发现的,这也是c++11所添加它的原因。

但存在一个例外,就是返回类型如果是类本身的指针或引用时,这个规则无效。就是基类可以返回base*或base&,派生类可以返回dervie*或derive&

结论:基类中的虚函数在派生类中隐含的也是一个虚函数,当派生类覆盖了某个虚函数时,该函数在基类总的形参必须与派生类中的形参严格匹配

d.如果将一个函数声明成final了,则之后任何尝试覆盖该函数的操作都将引发错误。

4.抽象基类

‘a.纯虚函数

新定义的disc_quote是一个打折通用的基类,而不是具体的折扣策略,所以我们不希望用户来定义一个disc_count,而是定义具体的折扣策略。

我们可以将disc_quote中的net_price定义为一个纯虚函数来实现。这样可以清晰的告诉用户当前这个net_price没有实际意义的。和普通虚函数不一样。

一个纯虚函数无需定义,我们通过在函数体的位置后面加上=0 即可。就可以将一个虚函数变为纯虚函数。其中=0只能出现在类内部的虚函数声明语句处。

注意:我们也可以为虚函数提供定义,不过函数体必须定义在类的外部,也就是说我们不能在类的内部为一个=0的函数提供函数体。

b.含有纯虚函数的类是抽象基类

含有(未经覆盖直接继承)纯虚函数的类是抽象基类,抽象基类负责定义接口,而后续的其他类可以覆盖接口,我们不能直接创建一个抽象基类的对象。

我们可以定义抽象基类的派生类对象,前提是覆盖了纯虚函数的接口。

注意:我们不能创建抽象基类的对象。

c.派生类构造函数只初始化它的直接基类

基类quote----->抽象基类disc_quote----->派生类bulk_quote

-->表示继承关系

那么我们定义bulk_quote的构造函数时只能初始化disc_quote,在由disc_quote的构造函数来初始化quote的成员。

关键概念重构:

重构负责重新设计类的体系以便将操作和/或数据从一个类移动到另一个类中,对于面向对象的应用程序来说,重构是一种很普遍的现象。

5.访问控制和继承

公有继承(public)、私有继承(private)、保护继承(protected)是常用的三种继承方式。

a. 公有继承(public)

公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。

b. 私有继承(private)

私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。

c. 保护继承(protected)

保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。

d.派生类向基类转换的可访问性

1只有当derive类公有的继承base类时,用户代码才能使用派生类向基类的转换,如果derive继承base的方式是受保护的或者私有的,则用户代码不能使用该转换。

2不论derive以什么方式继承base类,derive的成员函数和友元都能使用派生类向基类的转换,派生类向其直接基类的类型转换对于派生类的成员和友元来说是永久可访问的。

3如果derive继承base的方式是共有的或者受保护的,则derive的派生类的成员和友元可以使用derive向base的类型转换,反之,如果derive继承base的方式是私有的,则不能使用

e.通过在类的内部使用using 声明语句,我们可以将该基类的直接或间接基类中的任何可访问成员标记出来,using 声明语句中名字的访问权限由它所在的访问说明符来决定。

6.继承中的类作用域

每个类定义自己的作用域,在这个作用域内我们定义类的成员,当存在继承关系时,派生类的作用域嵌套在其基类作用域之内。如果一个名字在自己的作用域内无法解析,那么就会在基类中查找。

名字查找先于类型检查。

7.构造函数和拷贝控制

a.虚析构函数:使用delete一个动态对象时将执行其析构函数,当delete指针时,其指针的静态类型与被删除对象的动态类型不一样,但是编译器需执行动态类型的析构函数。我们可以通过在基类中将析构函数定义成虚函数来确保。

8.容器和继承

当我们使用容器存放继承体系中的对象时,通常必须采用简介存储的方式,因为不允许在容器中保存不同类型的元素,所以我们不能把具有继承关系的多种类型

的对象直接存放在容器中。

注意:当派生类对象被赋值给基类对象时,其中的派生类部分将被切掉,因此容器和存在继承关系的类型无法兼容。

在容器中放置(智能)指针而非对象

当我们希望在容器中存放具有继承关系的对象时,我们实际上存放的通常是基类的指针,更好的是存放智能指针,和往常一样,这些指针所指对象的动态类型可能是

基类类型,也可能是派生类类型。

正如我们可以把派生类的指针转换为基类的指针一样

我们也可以把派生类的智能指针转换为基类的智能指针。

std::vector<std::shared<quote>>basket;

时间: 2024-10-10 22:01:24

c++面向对象的程序设计的相关文章

第十篇 面向对象的程序设计

第十篇 面向对象的程序设计 阅读目录 一 面向对象的程序设计的由来 二 什么是面向对象的程序设计及为什么要有它 三 类和对象 3.1 什么是对象,什么是类 3.2 类相关知识 3.3 对象相关知识 3.4 对象之间的交互 3.5 类名称空间与对象/实例名称空间 3.6 小结 四 继承与派生 4.1 什么是继承 4.2 继承与抽象(先抽象再继承) 4.3 继承与重用性 4.4 组合与重用性 4.5 接口与归一化设计 4.6 抽象类 4.7 继承实现的原理(继承顺序) 4.8 子类中调用父类方法 五

走入计算机的第二十八天(面向对象的程序设计)

一  什么是面向对象的程序设计及为什么要有它 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了程序的复杂度 缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身. 应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等. 面向对象的程序设计的核心是

面向对象的程序设计:Object-oriented programming

在面向对象的程序设计(英语:Object-oriented programming,缩写:OOP)中,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象. 在现实世界里我们所面对的事情都是对象,如计算机.电视机.自行车等. 对象的主要三个特性: 对象的行为:可以对 对象施加那些操作,开灯,关灯就是行为. 对象的形态:当施加那些方法是对象如何响应,颜色,尺寸,外型. 对象的表示:对象的表示就相当于身份证,具体区分在相同的行为与状态下有什么不同. 比如 Animal(动物) 是一

python之面向对象的程序设计

第一:程序设计思想与发展历程(了解) 1940年以前:面向机器编程最早的是采用机器语言编程,也就是直接使用二进制码来表示机器能够识别的指令和数据.优点:机器语言由机器直接执行,速度快缺点:写起来非常困难,并且不容易修改 汇编语言:用助记符号代替机器指令的操作码,用地址符号或者标号代替指令或操作数的地址优点:比机器语言的二进制码编写方便些缺点:汇编语言本质上还是一种面向机器的语言,编写困难,易出错 脱离机器后:面向过程编程面向过程的结构化程序设计强调功能的抽象和程序的模块化, 它将解决问题的过程看

JavaScript 面向对象的程序设计记录笔记2(设计模式)

以下为JavaScript高级程序设计 第六章面向对象的程序设计6.2节 创建对象(设计模式部分)读书记录. 1)工厂模式: function createPerson(name, age, sex) { var o = new Obejct(); o.age = age; o.sex = sex; o.name = name; return o; } var person = createPerson('Tom', 12, 'male'); var person = createPerson(

JavaScript 面向对象的程序设计记录笔记

以下为JavaScript高级程序设计第六章面向对象的程序设计读书笔记记录. 对象存在两个属性: 数据属性/ 访问器属性. 数据属性包括四个值: Configurable: 默认值为true, 表示能否通过delete删除属性重新定义:能否修改属性特性,或者能否吧属性修改为访问器属性. Enumable:  表示能否通过for in循环返回属性.默认值为true. writable: 表示能否修改属性,默认值为true. Value:包含这个属性的数据值. 访问器属性包括四个值:Configur

Python进阶---面向对象的程序设计思想(一)

thon的面向对象 一.面向过程与面向对象的对比 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了程序的复杂度 缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身. 应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等. 面向对象的程序设计的核

python基础----面向对象的程序设计

面向对象的软件开发有如下几个阶段: 1.面向对象分析(object oriented analysis ,OOA) 2 面向对象设计(object oriented design,OOD) 3 面向对象编程(object oriented programming,OOP) 4 面向对象测试(object oriented test,OOT) 5 面向对象维护(object oriendted soft maintenance,OOSM) 1 #对象:学校----->归类 2 #共有的特征:商标为

js面向对象的程序设计笔记

chap6:面向对象的程序设计 面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象.前面提到过,ECMAScript 中没有类的概念,因此它的对象也与基于类的语言中的对象有所不同.ECMA-262 把对象定义为: “无序属性的集合, 其属性可以包含基本值. 对象或者函数. ” 严格来讲,这就相当于说对象是一组没有特定顺序的值.对象的每个属性或方法都有一个名字,而每个名字都映射到一个值.正因为这样(以及其他将要