C++ Primer (3RD) 重读笔记——基于对象的程序设计

第十三章 类

13.1 类定义

类定义包含两部分:类头(class head),由关键字class 及其后面的类名构成。类体(class body), 由一对花括号包围起来。类定义后面必须接一个分号或一列声明。

在类体中,对类的数据成员和成员函数进行声明,并指定这些类成员的访问级别。类体定义了类成员表(class member list)

13.1.1 数据成员

13.1.2 成员函数

13.1.3 成员访问

     信息隐藏(Information hiding)是为了防止程序的函数直接访问类类型的内部表示而提供的一种形式化机制。

公有成员(public member在程序的任何地方都可以被访问。

私有成员(private member只能被成员函数和类的友元访问。

被保护成员(protected member对派生类(derived class就像public 成员一样,对其他程序则表现得像private

13.1.4 友元

友元(friend)机制允许一个类授权其他的函数访问它的非公有成员。

13.1.5 类声明和类定义

13.2 类对象

类的定义,如类Screen不会引起存储区分配。只有当定义一个类的对象时,系统才会分配存储区。

13.3 类成员函数

13.3.1 inline 和非inline 成员函数

通常,在类体外定义的成员函数不是inline 的。但是,这样的函数也可以被声明为inline函数,可以通过显式地在类体中出现的函数声明上使用关键字inline或者通过在类体外出现的函数定义上显式使用关键字inline或者两者都用。

13.3.2 访问类成员

1.成员函数的定义可以引用任何一个类成员,无论该成员是私有的还是公有的,都不会破坏类访问限制。

2.成员函数可以直接访问它所属的类的成员,而无需使用点或箭头成员访问操作符。

13.3.3 私有与公有成员函数

13.3.4 特殊的成员函数

有一组特殊的成员函数可以管理类对象并处理诸如初始化,赋值,内存管理,类型转换以及析构等活动。这些函数通常由编译器隐式调用。

初始化成员函数被称为构造函数(constructor)每次定义一个类对象或由new 表达式分配一个类对象时都会调用它。构造函数的名字必须与类名相同。

13.3.5 const volatile 成员函数

为尊重类对象的常量性,编译器必须区分不安全与安全的成员函数(即区分试图修改类对象与不试图修改类对象的函数)

类的设计者通过把成员函数声明为const以表明它们不修改类对象。

只有被声明为const 的成员函数才能被一个const 类对象调用。关键字const 被放在成员函数的参数表和函数体之间。对于在类体之外定义的const 成员函数,我们必须在它的定义和声明中同时指定关键字const

把一个修改类数据成员的函数声明为const 是非法的。

13.3.6 mutable 数据成员

为了允许修改一个类的数据成员,即使它是一个const 对象的数据成员,我们也可以把该数据成员声明为mutable (易变的)

13.4 隐含的this 指针

每个类对象都将维护自己的类数据成员的拷贝。

13.4.1 何时使用this 指针

13.5 静态类成员

同全局对象相比,使用静态数据成员有两个优势:

1静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性。

2可以实现信息隐藏。静态成员可以是private 成员,而全局对象不能。

13.5.1 静态成员函数

13.6 指向类成员的指针

13.6.1 类成员的类型

函数指针不能被赋值为成员函数的地址,即使返回类型和参数表完全匹配: 1参数的类型和个数;2返回类型;3它所属的类类型。

13.6.2 使用指向类成员的指针

13.6.3 静态类成员的指针

13.7 联合一种节省空间的类

联合(union)是一种特殊的类,一个联合中的数据成员在内存中的存储是互相重叠的。

union 的成员可以被声明为公有,私有或保护的。

union 不能有静态数据成员或是引用成员。如果一个类类型定义了构造函数,析构函数或拷贝赋值操作符,则它不能成为union 的成员类型。

我们可以为union 定义成员函数,包括构造函数和析构函数。

13.8 位域(bit-field):一种节省空间的成员

有一种被称为位域(bit-field的特殊的类数据成员,它可以被声明用来存放特定数目的位。位域必须是有序数据类型。它可以有符号,也可以无符号。

13.9 类域

类体就定义了一个域。在类体中,每一个类成员的声明都向它的类域中引入了一个成员名。

13.9.1 类域中的名字解析

13.10 嵌套类

一个类可以在另一个类中定义,这样的类被称为嵌套类(nested class)。嵌套类是其外围类的一个成员。嵌套类的定义可以出现在其外围类的公有,私有或保护区中。

13.10.1 在嵌套类域中的名字解析

13.11 作为名字空间成员的类

目前给出的在名字空间中的类都是在全局名字空间域中定义的类。类也可以被定义在用户声明的名字空间中。在用户声明的名字空间中定义的类名只在该名字空间的域中可见,而在全局域或其他名字空间中不可见。这意味着,该类名不会与在其他名字空间中声明的名字冲突。

13.12 局部类

类也可以定义在函数体内,这样的类被称为局部类(local class)。局部类只在定义它的局部域内可见。与嵌套类不同的是,在定义该类的局部域外没有语法能够引用局部类的成员。

 

 

第十四章 类的初始化,赋值和析构

14.1 类的初始化

14.2 类的构造函数

构造函数与类同名,我们以此来标识构造函数。

14.2.1 缺省构造函数

14.2.2 限制对象创建

14.2.3 拷贝构造函数

14.3 类的析构函数

提供构造函数的一个目的是为了自动获取资源。

析构函数(destructor)为生命期即将结束的类对象返还相关的资源或者自动释放资源。它是构造函数的互补。

14.3.1 显式的析构调用

14.3.2 可能出现的程序代码膨胀

14.4 类对象数组和vector

14.4.1 堆数组的初始化

14.4.2 类对象的vector

14.5 成员初始化表

14.6 按成员初始化

14.6.1 成员类对象的初始化

14.7 按成员赋值

14.8 效率问题

一般来说,通过指针或引用向一个函数传递一个类对象比传值更有效率。

第十五章 重载操作符和用户定义的转换

15.1 操作符重载

操作符重载使得程序员能够为类类型的操作数定义预定义的操作符版本。

15.1.1 类成员与非成员

一般应该怎样决定是把一个操作符声明为类成员还是名字空间成员呢? 在某些情况下, 程序员没有选择的余地。

1.如果一个重载操作符是类成员,那么只有当跟它一起被使用的左操作数是该类的对象时,它才会被调用。如果该操作符的左操作数必须是其他的类型,那么重载操作符必须是名字空间成员。

2.C++要求,赋值= 下标([]) 调用(()) 和成员访问箭头(->) 操作符(.)必须被定义为类成员操作符。任何把这些操作符定义为名字空间成员的定义都会被标记为编译时刻错误。

15.1.2 重载操作符的名字

只有在C++预定义操作符集中的操作符才可以被重载。

+

-

*

/

%

^

&

|

~

!

,

=

< 

> 

<=

>=

++

--

<< 

>> 

==

!=

&&

||

+=

-=

/=

%=

^=

&=

|=

*=

<<=?

>>=

[]

()

->

->*

new

new[]

delete

delete[]

 

 

 

类的设计者不能声明一个没有出现在表格中的重载操作符。

对于内置类型的操作符,它的预定义意义不能被改变。

15.1.3 重载操作符的设计

15.2 友元

友元声明的最常见用法是,允许非成员的重载操作符访问一个视其为朋友的类的私有成员。

虽然友元声明的主要用处是在重载操作符上,但是,在某些情况下,一个名字空间函数,另一个在此之前被定义的类的成员函数,或者一个完整的类必须声明为友元。

15.3 操作符=

一个类对象向该类的另一个对象的赋值可通过拷贝赋值操作符来执行。

15.4 操作符[]

我们可以为表示容器抽象并能够获取其单独元素的类定义下标操作符operator[]()

15.5 操作符operator()

我们可以为类类型的对象重载函数调用操作符。如果一个类类型被定义来表示一个操作时,则可以为这个类类型重载函数调用操作符,以便调用这个操作。

15.6 操作符->

我们也可以为类类型的对象重载成员访问操作符箭头,它必须被定义为一个类的成员函数。它的作用是赋予一个类类型与指针类似的行为。它通常被用于一个代表“智能指针(smartpointer)”的类类型。也就是说,一个类的行为很像内置的指针类型,但是支持某些额外的功能。

 

15.7 操作符++--

15.8 操作符new delete

15.8.1 数组操作符new[]delete[]

15.8.2 定位操作符new()delete()

15.9 用户定义的转换

15.9.1 转换函数

转换函数(conversion function)是一种特殊类型的类成员函数。它定义了一个由用户定义的转换,以便把一个类对象转换成某种其他的类型。在类体中通过指定关键字operator并在其后加上转换的目标类型后,我们就可以声明转换函数。

15.9.2 用构造函数作为转换函数

在一个类的构造函数中,凡是只带一个参数的构造函数,都定义了一组隐式转换,把构造函数的参数类型转换为该类的类型。

15.10 选择一个转换

用户定义的转换是由转换函数或构造函数执行的转换。

当试图转换一个值时,有可能存在两个不同的用户定义的转换序列,它们都能够被用来把该值转换成目标类型。当不只一个转换序列可以被应用时,编译器必须选择最好的序列执行转换。

15.10.1 函数重载解析——回顾

 

 

第十六章  类模板

C++中模板是泛型编程的基础。(In C++, templates are the foundation for generic programming.)。

16.1 类模板定义

    函数模板是和类型无关的函数定义,它被当作是公式用来生成特定类型版本的函数。

编译器一旦确定了模板的实参,就会实例化模板函数。

编译器承担了为每种类型重写函数的枯燥的任务。

要明确的是编译器是在编译期完成这些任务的。

16.2 类模板实例化

类模板定义指定了怎样根据一个或多个实际的类型或值的集合来构造单独的类。

16.2.1 非类型参数的模板实参

类模板参数也可以是一个非类型模板参数。

在模板实参的类型和非类型模板参数的类型之间允许进行一些转换,能被允许的转换集是函数实参上被允许的转换的子集:

1左值转换, 包括从左值到右值的转换, 从数组到指针的转换, 以及从函数到指针的转换。

2限定修饰转换。

3提升

4整值转换

16.3 类模板的成员函数

与非模板类一样,类模板的成员函数也可以在类模板的定义中定义,在这种情况下,该成员函数是inline 成员函数。或者,成员函数也可以被定义在类模板定义之外。

16.3.1 Queue QueueItem 模板成员函数

16.4 类模板中的友元声明

有三种友元声明可以出现在类模板中:

1非模板友元类或友元函数。

2绑定的(bound)友元类模板或函数模。

3非绑定的(unbound)友元类模板或函数模板。

16.4.1 Queue QueueItem 的友元声明

16.5 类模板的静态数据成员

类模板也可以声明静态数据成员。

类模板的每个实例都有自己的一组静态数据成员。

16.6 类模板的嵌套类型

16.7 成员模板

函数或类模板可以是一个普通类的成员,也可以是一个类模板的成员。成员模板的定义看起来像一般模板的定义,成员定义前面加上关键字template 及模板参数表。

16.8 类模板和编译模式

类模板定义只是无限多个类类型的定义“的”规范描述(prescription)而已。模板定义本身并没有定义任何一个类类型。

16.8.1 包含编译模式

在包含编译模式下,类模板的成员函数和静态成员的定义必须被包含在要将它们实例化的所有文件中, 对于类模板定义中被定义为inline 的内联成员函数, 这是自动发生的。

16.8.2 分离编译模式

在分离编译模式下, 类模板定义和其inline 成员函数定义都被放在头文件中, 而非inline成员函数和静态数据成员被放在程序文本文件中。

16.8.3 显式实例声明

16.9 类模板特化

16.10 类模板部分特化

16.11 类模板中的名字解析

16.12 名字空间和类模板

与任何其他的全局域定义一样,类模板定义也可以被放在名字空间中。对于这样的类模板定义其意义与在全局域中定义的类模板相同。

16.13 模板数组类

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值