第14章总结
本节阅读量:在本章中,探索了C++的核心——类!这是教程系列中最重要的一章,它为后面的大部分内容奠定了基础。
章节回顾
在面向过程编程中,重点是创建实现程序逻辑的“过程”(在C++中称为函数)。将数据对象传递给这些函数,这些函数对数据执行操作,然后可能返回一个结果供调用方使用。
使用面向对象编程(通常缩写为OOP),重点是创建包含属性和一组定义良好的行为的程序定义的数据类型。
类不变量是一种条件,它必须在对象的整个生存期内为真,以便对象保持有效状态。违反的类不变量的对象被称为处于无效状态,并且进一步使用该对象可能会导致意外或未定义的行为。
类是程序定义的复合类型,它捆绑了数据和处理该数据的函数。
属于类类型的函数称为成员函数。调用成员函数的对象通常称为隐式对象。不是成员函数的函数称为非成员函数,以将它们与成员函数区分开来。如果类类型没有数据成员,则更推荐使用命名空间。
const成员函数是一个成员函数,它保证不会修改对象或调用任何非const成员函数(因为它们可能会修改对象)。不(并且永远不会)修改对象状态的成员函数应成为const,以便可以在非常量对象和常量对象上调用它。
类类型的每个成员都有一个称为访问级别的属性,该属性确定谁可以访问该成员。访问级别系统有时非正式地称为访问控制。访问级别是基于每个类而不是基于每个对象定义的。
public成员是类类型的成员,对如何访问它们没有任何限制。任何人都可以访问公共成员。这包括同一类的其他成员。公共成员也可以被公共访问,这是我们所称的存在于给定类类型的成员之外的代码,包括非成员函数以及其他类类型的成员。
默认情况下,结构体的所有成员都是公共成员。
私有成员是只能由同一类的其他成员访问的类类型的成员。
默认情况下,类的成员是私有的。具有私有成员的类不再是聚合,因此不能再使用聚合初始化。考虑以“m_”前缀开头命名私有成员,以帮助将它们与局部变量、函数参数和成员函数的名称区分开来。
可以通过使用访问说明符来显式设置成员的访问级别。结构体通常应避免使用访问说明符,以便所有成员都默认为public。
访问函数是一个普通的public成员函数,其任务是检索或更改私有成员变量的值。访问函数有两种风格:getter和setter。Getter(有时也称为访问器)是返回私有成员变量值的公共成员函数。Setter(有时也称为mutator)是设置私有成员变量值的公共成员函数。
类类型的接口定义类类型的用户将如何与类类型的对象交互。由于只能从类类型外部访问公共成员,因此类类型的公共成员形成其接口。由公共成员组成的接口有时称为公共接口。
类类型的实现由实际使类按预期行为执行的代码组成。这包括存储数据的成员变量,以及包含程序逻辑和操作成员变量的成员函数体。
在编程中,数据隐藏(也称为信息隐藏或数据抽象)是一种通过对用户隐藏程序定义的数据类型的实现来强制实现接口和实现分离的技术。
术语封装有时也用于指代数据隐藏。然而,该术语也用于指将数据和功能捆绑在一起(不考虑访问控制)。
定义类时,最好先声明公共成员,然后声明私有成员。这突出了公共接口,并淡化了实现细节。
构造函数是一个特殊的成员函数,用于初始化类类型对象。必须找到匹配的构造函数才能创建非聚合类类型对象。
成员初始值设定项列表允许您从构造函数中初始化成员变量。应按在类中定义成员变量的顺序列出它们。与在构造函数主体中分配值相比,优先使用成员初始值设定项列表来初始化成员。
不带参数(或具有所有默认参数)的构造函数称为默认构造函数。如果用户没有提供初始化值,则使用默认构造函数。如果非聚合类类型对象没有用户声明的构造函数,编译器将生成默认构造函数(以便类可以被值初始化或默认初始化)。此构造函数称为隐式默认构造函数。
允许构造函数将初始化委托给同一类类型的另一个构造函数。这个过程有时被称为构造函数委托,这样的构造函数被称为委托构造函数。构造函数可以委托或初始化,但不能同时委托和初始化。
临时对象(有时称为匿名对象或未命名对象)是没有名称且仅在单个表达式期间存在的对象。
拷贝构造函数是用于使用相同类型的现有对象初始化对象的构造函数。如果不为类提供拷贝构造函数,C++将为您创建一个执行成员级初始化的public隐式拷贝构造函数。
仿佛规则说,编译器可以随意修改程序,以产生更优化的代码,只要这些修改不影响程序的“可观察行为”。“仿佛”规则的一个例外是拷贝省略。拷贝省略是一种编译器优化技术,允许编译器删除不必要的对象复制。当编译器优化掉对拷贝构造函数的调用时,说构造函数已被省略。
编写的将值转换为程序定义类型或从程序定义类型转换为值的函数称为用户定义转换。可以用于执行隐式转换的构造函数称为转换构造函数。默认情况下,所有构造函数都是转换构造函数。
可以使用explict关键字来告诉编译器,构造函数不应用作转换构造函数。这样的构造函数不能用于执行拷贝初始化或拷贝列表初始化,也不能用于执行隐式转换。
默认情况下,使任何接受单个参数的构造函数explict。如果类型之间的隐式转换在语义上是等效的,并且是性能优化的(例如从std::string到std:∶string_view的转换),则可以考虑使构造函数成为非explict的。不要使拷贝或移动构造函数explict,因为它们不执行转换。
