跳转到内容

C++ 编程:编程语言范式

来自维基教科书,开放的书籍,面向开放的世界

编程范式

[编辑 | 编辑源代码]

编程范式 是一种基于不同概念的编程模型,它塑造了程序员设计、组织和编写程序的方式。一个 多范式编程语言 允许程序员选择特定的单一方法或混合不同编程范式的部分。C++ 作为一种多范式编程语言,支持使用过程式或面向对象编程的单一或混合方法,并混合使用泛型甚至函数式编程概念。

过程式编程

[编辑 | 编辑源代码]

过程式编程 可以定义为 命令式编程 的一种子类型,它是一种基于过程调用的编程范式,其中 语句 被组织成过程(也称为子例程或函数)。过程调用是模块化的,并受作用域的约束。过程式程序由一个或多个 模块 组成。每个模块由一个或多个 子程序 组成。模块可以包含过程、函数、子例程或方法,具体取决于编程语言。过程式程序可能具有多个级别或作用域,子程序定义在其他子程序中。每个作用域可以包含在外部作用域中不可见的名称。

过程式编程相对于简单的顺序编程提供了许多优势,因为过程式代码

  • 更容易阅读,更容易维护
  • 更加灵活
  • 有利于良好的程序设计实践
  • 允许模块以 代码库 的形式重复使用。

注意
如今,很少看到严格使用过程式编程范式的 C++,它主要只用于小型演示或测试程序。

静态类型

[编辑 | 编辑源代码]

类型 指的是计算机语言如何处理其变量,以及它们如何通过 类型 来区分。变量是在程序执行期间程序使用的值。这些值可以改变;它们是可变的,因此得名。静态类型 通常会生成执行速度更快的编译代码。当编译器知道正在使用的确切类型时,它可以生成更容易执行正确操作的机器代码。在 C++ 中,变量需要在使用之前进行定义,以便编译器知道它们的类型,因此它是静态类型的。非静态类型的语言被称为 动态类型

静态类型通常在编译时更可靠地发现类型错误,从而提高编译程序的可靠性。简而言之,这意味着“圆 peg 不适合方形孔”,因此当类型导致歧义或不兼容的使用时,编译器会报告它。然而,程序员对类型错误的普遍程度以及静态类型将捕获多少已编写错误存在分歧。静态类型倡导者认为,当程序经过类型检查时,它们会更可靠,而动态类型倡导者则指出已证明可靠的动态代码以及小型错误数据库。因此,静态类型的价值 presumably 随着类型系统的强度增加而增加。

静态类型系统比它限制不太强大的语言结构更限制强大语言结构的使用。这使得强大的结构更难使用,因此将选择“适合问题的正确工具”的责任交给了程序员,否则他们可能倾向于使用最强大的工具。选择过于强大的工具可能会导致额外的性能、可靠性或正确性问题,因为 理论限制 限制了可以从强大的语言结构中预期得到的属性。例如,不加区别地使用 递归全局变量 可能会导致有据可查的不利影响。

静态类型允许构建不太可能被用户意外误用的库。这可以用作传达库开发人员意图的额外机制。

类型检查

[编辑 | 编辑源代码]

类型检查 是验证和强制类型约束的过程,它可以在编译时或运行时发生。编译时检查,也称为 静态类型 检查,是在编译程序时由编译器执行的。运行时检查,也称为 动态类型检查,是在程序运行时由程序执行的。如果类型系统确保类型之间的转换必须有效或导致错误,则称编程语言为 强类型。另一方面,弱类型 语言没有这样的保证,通常允许类型之间的自动转换,这些转换可能没有有用的目的。C++ 处于中间位置,允许自动类型转换和程序员定义的转换,允许在解释一种类型为另一种类型方面几乎完全灵活。将一种类型的变量或表达式转换为另一种类型称为 类型转换

面向对象编程

[编辑 | 编辑源代码]

面向对象编程 可以看作是过程式编程的扩展,其中程序由称为 对象 的单个单元的集合组成,这些单元具有不同的目的和功能,对 实现 的依赖性有限或没有。例如,汽车就像一个对象;它可以将你从 A 点带到 B 点,而无需知道汽车使用什么类型的发动机或发动机的运作方式。面向对象的语言通常提供一种方法来 记录 对象可以和不能做什么,就像驾驶汽车的说明书一样。

对象和类

[编辑 | 编辑源代码]

一个 对象成员方法 组成。成员(也称为 数据成员特征属性特性)描述了对象。方法通常描述与特定对象相关的操作。将对象视为名词,其成员为描述该名词的形容词,其方法为可由该名词执行或对该名词执行的动词。

例如,一辆跑车就是一个对象。它的成员可能包括高度、重量、加速度和速度。对象的成员只是保存关于该对象的数据。跑车的一些方法可以是“驾驶”、“停车”、“比赛”等等。方法在与跑车关联之前并没有什么意义,成员也是如此。

让我们构建跑车对象的“蓝图”称为。类不会告诉我们跑车的速度有多快,或者它的颜色是什么,但它会告诉我们,我们的跑车将有一个代表速度和颜色的成员,它们分别是一个数字和一个词。类还会为我们制定方法,告诉汽车如何停车和驾驶,但这些方法仅凭蓝图无法采取任何行动——它们需要一个对象才能产生效果。

C++ 中的类与 C 中的结构相同;不同之处在于类用户可以通过 private 选项隐藏数据。在 C++ 中,对象是类的实例,它被视为一个内置变量,其中包含多个值。

封装是信息隐藏(对用户而言)的原则,是隐藏类数据结构并允许通过公共接口更改数据(在该接口中,传入值会经过有效性检查)的过程,因此它不仅允许隐藏对象中的数据,还允许隐藏行为。这防止了接口的客户端依赖于将来可能发生更改的实现部分,从而使这些更改更容易进行,也就是说,无需更改客户端。在现代编程语言中,信息隐藏的原则以多种方式体现出来,包括封装和多态性。

继承描述了两种(或多种)对象类型或类之间的关系,其中一种被称为另一种的“子类型”或“子类”;因此,“子类”对象被认为继承了父类的特性,从而允许共享功能。这使程序员能够重复使用或减少代码,并简化软件的开发和维护。

继承通常也包括子类型化,其中一种类型的对象被定义为另一种类型的更专门的版本(参见Liskov 替换原则),尽管非子类型继承也是可能的。

继承通常通过描述对象类继承层次结构(也称为继承链)排列来表达,继承层次结构是由它们的继承关系创建的树状结构。

例如,人们可以创建一个名为“哺乳动物”的可变类,它具有诸如进食、繁殖等特性;然后定义一个子类型“猫”,它继承了这些特性,而无需显式地对其进行编程,同时添加了诸如“追捕老鼠”等新特性。这允许不同类型对象之间的共性只表达一次并重复使用多次。

在 C++ 中,我们可以拥有与其他类相关的类(可以通过使用较旧的、预先存在的class来定义一个类)。这会导致一种情况,即新的类具有旧类所有的功能,并且还引入了它自己特有的功能。我们这里不是指组合,即给定的类包含另一个类,而是指派生,即给定的类是另一个类。

当我们讨论本书的类继承部分中的类(和结构)继承时,将进一步解释这个 OOP 特性。

如果想要同时使用多个完全正交的层次结构,例如允许“猫”从“卡通人物”和“宠物”以及“哺乳动物”继承,那么我们正在使用多重继承

多重继承
[编辑 | 编辑源代码]

多重继承是指一个类可以继承两个或多个类(分别称为基类、父类、祖先类或超类)的属性的过程。

注意
在某些类似的语言中,多重继承以各种方式受到限制,以保持语言的简单性,例如,只允许从一个真正的类和多个“接口”继承,或完全禁止多重继承。C++ 将多重继承的全部功能交给了程序员,但它只在极少数情况下需要,并且(与大多数技术一样),如果使用不当会使代码复杂化。由于 C++ 对多重继承的处理方式,C++ 不需要为其他面向对象语言中通常称为“接口”、“特性”或“mixin”的特殊语言结构提供单独的语言设施,因为 C++ 的类本身已经提供了这种功能。

这将在本书的C++ 类继承部分中详细介绍。

多态性
[编辑 | 编辑源代码]

多态性允许为几个相关但不同的目的重复使用同一个名称。多态性的目的是允许使用一个名称来表示一个通用类。根据数据类型,执行通用情况的特定实例。

多态性的概念更广泛。每次我们使用具有相同名称但实现不同的两个函数时,就会出现多态性。它们也可能在接口上有所不同,例如,通过接收不同的参数。在这种情况下,选择哪个函数由重载解析确定,并在编译时执行,因此我们将其称为静态多态性

动态多态性将在类部分中深入介绍,在那里我们将讨论它在派生类中重新定义方法时的使用。


泛型编程

[编辑 | 编辑源代码]

泛型编程多态性是一种编程风格,它强调允许一个值采用不同类型的技术,只要满足某些契约,例如子类型签名。简而言之,泛型编程是基于找到高效算法的最抽象表示。模板普及了泛型的概念。模板允许编写代码时不考虑最终使用它的类型。模板是在标准模板库 (STL)中定义的,泛型编程就是在这里引入到 C++ 中的。

自由格式

[编辑 | 编辑源代码]

自由格式指的是程序员如何编写代码。基本上,除了 C++ 的语义规则之外,没有关于如何选择编写程序的规则。只要是合法的 C++,任何 C++ 程序都应该可以编译。

一些程序员使用 C++ 的自由格式性质来编写混淆的 C++ 代码(故意编写难以理解的代码)(或者说滥用,这取决于你的观点)。在适当的上下文中,这也可以被视为一种工艺的展示(非功能性但对语言的艺术性控制),但一般来说,混淆的用途只被视为一种有用的源代码安全机制,确保源代码更难被第三方故意分析、复制或使用。如果对编译器有足够的了解,还可以设计源代码,使其在编译后的形式中保留“水印”,从而可以将它追溯到原始源代码。

华夏公益教科书