第七章 类 c++primer

来源:互联网 发布:制衣打飞软件 编辑:程序博客网 时间:2024/06/05 10:42

c++中使用类定义自己的数据类型。
数据抽象帮助将对象的具体实现与对象能执行的操作分离开来
类的基本思想是数据抽象和封装。
数据抽象是一种依赖于接口和实现分离的编程技术

类的接口包括用户所能执行的操作;类的实现包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数

封装实现了类的接口和实现的分离

类要实现数据抽象和封装,必须首先定义一个抽象数据类型

7.1定义抽象数据类型
引入this:使得成员函数可以使用调用这个函数的对象的成员

引入const 成员函数:this是一个指向类类型的非常量版本的常量指针type(或者class) * const;所以不能绑定到一个常量对象上,随意导致常量对象不能调用普通成员函数,这就需要this指向常量对象;对于普通函数而且this是一个普通指针可以这样声明this:const Sales_data *const;但是this是隐式的不会出现在参数列表;所以要选择一个位置来将this声明为指向常量的指针,c++让const跟在函数参数列表后面来解决,这样的成员函数称为常量成员函数

常量对象,常量对象的引用或指针都只能调用常量成员函数

类作用域和成员函数:
类本身是一个作用域,类的成员函数嵌套定义在类作用域内,编译器处理类时分两步:先编译成员声明,然后才是成员函数,所以成员函数可以随意使用成员名,无须在意声明顺序

在类的外部定义的成员函数:
在外部定义的成员函数必须与她在类内的声明匹配,包括返回类型,参数列表函数名,如果被声明称常量成员函数参数列表后加const,类外部定义的成员的名字必须包含所属的类名(使用作用域运算符)。

定义一个返回this对象的函数:如combine类似于+=
return *this;return语句解引用this指针获得调用该函数的对象

7.1.3定义类相关的非成员函数
这些函数属于类接口的组成部分,但又不属于类本身。

定义它们的方式与普通函数一样,生命和定义分开,声明和类声明放在同一个头文件内;
默认情况下拷贝类对象拷贝的是对象的数据成员

7.1.4 构造函数:初始化对象
任务:初始化类对象的数据成员,无论何时只要类的对象被创建就会执行构造函数;
特点:名字和类名相同,没有返回类型;其他与普通函数类似

构造函数没有不能被声明成const,构造函数在const对象构造过程中可以向其写值

定义构造函数:
。。。=default;//c++11新规定指定默认构造函数,可以和类声明一起出现在类内部,也可以作为类定义出现在类外部

构造函数初始值列表:她负责为构造函数新建的对象的一个或几个数据成员赋初值。构造函数初始值是成员名字的一个列表每个名字后面紧跟括号括起来的(或者在花括号内的)成员初始值;不同成员初始值用逗号隔开。
函数体是空的,这是因为构造函数的唯一目的就是为数据成员赋初值

在类外部定义的构造函数:和其他成员函数一样,外部定义的构造函数也必须指明构造函数是哪个类的成员,她执行构造函数体而没有初始值列表;

7.1.5拷贝赋值析构
除了定义类对象初始化,类还要控制拷贝,赋值,销毁对象时发生的行为
对象在几种情况下会被拷贝:如初始化变量以及以值的方式传递或返回一个对象等

使用赋值运算符时会发生赋值

对象不再存在时执行销毁操作

**很对需要动态内存的类能(而且应该)使用vector或者string对象管理必要的存储空间

7.2访问控制与封装

public:定义类的接口,在整个程序内可见

private:该说明符之后的成员可以被类的成员函数访问但是不能被使用该类的代码访问

使用public和struct定义类的唯一区别是默认访问权限不同

7.2.1友元:提供了对类的非公有成员的访问

必须在类定义内部声明友元
一般来说最好最好在类定义的开始或结束前集中声明友元(虽然不受类作用域约束)

友元的声明仅仅指定了访问权限,而非普通意义上的函数声明,如果我们希望类的用户能够调用某个友元函数,就必须在友元声明之外再专门对函数进行一次声明

7.3其他
除了定义书聚合函数成员之外,类还可以定义某种类型在类中的类型别名

inline可以在类内部声明或者外部定义中使用关键inline;

无需在类声明和定义的地方同时说明inline,最好只在类外部定义的地方声明inline

可变数据成员:mutable即使在const对象中也可以改变她声明的成员

类数据成员初始值
**类内初始值必须使用=的初始化形式或者花括号括起来的直接初始化形式

7.3.2返回*this的成员函数

7.3.4友元声明和作用域
即使是用声明友元的类的成员函数调用该友元函数,他也必须是被声明过的

7.4类的作用域

作用域和定义在在类外部的成员:
一个类就是一个作用域的事实很好的解释了为什么当我们在类的外部定义成员函数时必须同时提供类名和函数名;类的外部成员名字被隐藏了

声明了类名之后,定义的剩余部分就在类的作用域内了,包括参数列表和函数体,可以直接使用无需再次授权了,但是函数的返回类型通常出现在函数名之前,所以如果函数定义在类的外部,返回类型使用的名字都位于类的作用域之外,必须指明

7.4.1名字查找与类的作用域
名字查找:寻找与所用名字最匹配的声明的过程,从所在快开始,只向前查找,由内向外;

定义在类内部的成员函数,解析其中的名字方式与上述查找规则有所区别;
类的定义分两步:
* 首先,编译成员的声明,
* 直到类全部可见后才编译函数体,
编译器处理完全部声明之后才会处理函数定义

两阶段的处理方式只适用于成员函数中使用的名字。声明中使用的名字,包括返回类型或者参数列表中使用的名字,都必须使用前确保可见

类型名的定义通常出现在类的开始处,这样就能确保所用使用该类型的成员都出现类名定义之后

成员函数内使用的名字的 解析顺序:函数内查找,函数所在的类内查找,类外查找,如果类内有成员与函数用的名字同名,但是我们想要的是外部的这时可以使用全局作用域运算符: , ::

7.5构造函数再谈
如果成员是const,引用或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值

建议:使用构造函数初始值(初始化和赋值的区别,初始化直接初始化数据成员,而赋值是先初始化,在赋值,所以养成使用构造函数初始值的习惯.

成员初始化的顺序构造函数初始值列表只说明初始化成员的值,并不限定初始化的具体顺序,成员初始化的顺序与他们在类定义中出现的顺序一致,第一个成员先初始化,然后第二个。。

最好另构造函数初始化顺序与成员函数声明顺序相同,最好不要用一个成员去初始化其他成员

默认是惨和构造函数:

委托构造函数:他使用自己所属类的其他构造函数执行他自己的初始化过程,他把自己的一些职责委托给了其他构造函数,何其她构造函数一样她也有一个初始值列表和一个函数体

7.5.3默认构造函数的作用
对象被默认初始化或值初始化时自动执行默认构造函数,默认构造函数在以下情形使用:
* 在块作用域内不使用任何初始值定义一个非静态变量或者数组时
* 当一个类本身含有类类型的成员且使用合成的默认构造函数时
* 当类类型的成员没有在构造函数初始值列表中显示初始化时
* 当数组初识化过程中我们提供的初始值数量少于数组大小时
* 我们不使用初始值定义一个局部静态变量是

7.5.4隐式的类类型转换

能通过一个实参调用的构造函数定义了一条从构造函数实参类型到类类型隐式转换的规则
* 只允许一步类类型转换
* 类类型转换不总是有效

抑制构造函数定义的隐式转换:将构造函数声明为explicit
explicit构造函数只能用于直接初始化,不能用于拷贝初始化的过程

为转换显示的使用构造函数

7.5.5聚合类
所有成员public,没有构造函数,没有类内初始值,没有基类虚函数,他的初始化是使用花括号括起来的成员初始值列表,初始值的顺序必须与声明顺序一致;

7.5.6字面值常量类
数据成员都是字面值类型的聚合类是字面值常量类:

PS:常量表达式是指值不会改变并且编译过程就能得到结果的表达式,显然字面值常量是,用常量表达式初始化的const对象也是
字面值类型:算术类型,引用,指针都是字面值类型、枚举也是、字面值常量类
constexpr函数:能用于常量表达式的函数,他的返回类型,参数类型都是字面值常量,函数中有且只有一条返回语句,她在编译过程中就可以得到结果;

constexpr构造函数:尽管构造函数不能是const的但字面值常量类的构造函数可以是constexpr

7.6类的静态成员
让某些成员与类相关而不是对象:通过在成员声明前加上static使其与类关联在一起,静态成员可以是public也可以是private,静态数据成员可以是常量引用指针类类型等
某个类的静态数据对象为该类所有对象共享;

类似,静态成员函数也不与任何对象绑定在一起,他们不包括this指针,也就不能声明成const

使用类的静态成员:使用作用域运算符直接访问静态成员

虽然静态成员对象不属于类的某个对象,但是我们可以使用对象,引用,指针来访问静态成员

函数定义内,成员函数不用使用作用域运算符就能访问静态成员

定义静态成员
和其他成员函数一样,既可以在类的内部定义也可以在类的外部定义成员函数,挡在外部定义时,不能重复关键字static,该关键字只能在类内部声明语句出现;

静态数据成员不属于任何一个对象,她们并不是在创建类的对象时被定义的,她们不是有构造函数初始化的,而且一般来说,不能在类的内部初始化静态数据,必须在外部定义和初始化每个静态成员,
double Acount::interestRate=initRate();
interestRate是Acount的静态成员,类型double,从类名开始这条定义语句就在类的作用域内了,所以可以直接使用initRate()函数,虽然她是私有的,但是可以用来初始化interestRate

最好把静态数据成员的定义与其他非内联函数的定义放在同一个文件中

静态成员的类内初始化:要求静态成员必须是字面值常量类型的constepr,初始值必须是常量表达式;
如果仅限于编译器可以替换她的值的使用场景,则初始化一个const或者constexpr static不需要分别定义,否则将它用于值不能替换的场景中,必须提供一条定义语句,类内部提供了初始值,类外部不能在制定一个初始值了

静态数据成员的类型可以是不完全类型,可以是他所属的类类型,但是普通成员只能声明所属类的指针或者引用;另一个区别是静态成员可以作为默认实参

0 0
原创粉丝点击