-
对象:具备属性和行为这两种要素,对象之间通过发送和接收消息互相联系。
-
在C++中,每个对象都是由数据和函数(即操作代码)这两部分组成。调用对象中的函数就是向该对象传送一个消息(message),要求该对象实现某一行为(功能)。
-
封装性(encapsulation)
- 一是将有关的数据和操作代码封装在一个对象中,形成一个基本单位,各个对象之间相对独立,互不干扰。
- 二是将对象中某些部分对外隐蔽,即隐蔽其内部细节,只留下少量接口,以便与外界联系,接收外界的消息。这叫做信息隐蔽(imformation hiding)。信息隐蔽还有利于数据安全,防止无关的人了解和修改数据。
- C++的对象中的函数名就是对象的对外接口,外界可以通过函数名来调用这些函数来实现某些行为(功能)。
-
抽象(abstraction):将有关事物的共性归纳、集中的过程。表示同一类事物的本质。
- 类是对象的抽象,而对象则是类的特例,或者说是类的具体表现形式。
- 对象就是类类型的一个变量。可以说类是对象的模板,是用来定义对象的一种抽象类型。
- 类是抽象的,不占用内存,而对象是具体的,占用存储空间。
-
继承与重用
- 采用继承的方法可以很方便地利用一个已有的类建立一个新的类。即“软件重用”(software reusability) 的思想。
- 基类,子类,派生类。
-
多态性(polymorphism): 由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应。
对象 = 算法 + 数据结构 程序 = (对象+对象+对象+…) + 消息 或 程序 = 对象s + 消息 “对象s”表示多个对象。**消息的作用**就是对对象的控制。程序设计的关键是设计好每一个对象,及确定向这些对象发出的命令,使各对象完成相应操作。
-
面向对象的软件工程
- 面向对象分析(object oriented analysis,OOA)
- 面向对象设计(object oriented design,OOD)
- 面向对象编程(object oriented programming,OOP)
- 面向对象测试(object oriented test,OOT)
- 面向对象维护(object oriented soft maintenance,OOSM)
-
声明类类型
- 不能把类中的全部成员与外界隔离,一般是把数据隐蔽起来,而把成员函数作为对外界的接口。
- 如果在类的定义中既不指定
private
,也不指定public
,则系统就默认为是private
。 - 用
struct
声明的类,如果对其成员不作private
或public
的声明,系统将其默认为public
。 - 成员访问限定符(member access specifier)。
private
public
protected
protected
声明的成员称为受保护的成员,它不能被类外访问(这点与私有成员类似),但可以被派生类的成员函数访问。
class 类名 { private: 私有的数据和成员函数; public: 公用的数据和成员函数; };
-
定义对象的方法
- 先声明类类型,然后再定义对象
- 在声明类类型的同时定义对象
- 不出现类名,直接定义对象
-
**类的成员函数**
-
使用类函数时,要注意调用它的权限(它能否被调用)以及它的作用域(函数能使用什么范围中的数据和函数)。
-
本类中
private
函数。作用是支持其他函数的操作,是类中其他成员的工具函数(utility function),类外用户不能调用这些私有的工具函数。 -
类外定义成员函数
"∷"
是作用域限定符(field qualifier)或称作用域运算符,用它声明函数是属于哪个类的。- 如果在作用域运算符
“∷”
的前面没有类名,或者函数名前面既无类名又无作用域运算符“∷”
,如∷display( ) 或 display( )
,则表示display
函数不属于任何类,这个函数不是成员函数,而是全局函数,即非成员函数的一般普通函数。 - 类函数必须先在类体中作原型声明,然后在类外定义
-
类的成员函数也可以指定为内置函数(
inline
)。- 在程序调用这些成员函数时,并不是真正地执行函数的调用过程(如保留返回地址等处理),而是把**函数代码嵌入程序的调用点。**这样可以大大减少调用成员函数的时间开销。
- 类内定义的成员函数,可以省略
inline
,因为这些成员函数已被隐含地指定为内置函数 - 如果在类体外定义
inline
函数,则必须将类定义和成员函数的定义都放在同一个头文件中(或者写在同一个源文件中),否则编译时无法进行置换(将函数代码的拷贝嵌入到函数调用点)。
-
-
成员函数的存储方式
- 一个对象所占的空间大小只取决于该对象中数据成员所占的空间,而与成员函数无关。函数代码是存储在对象空间之外的。
- 调用不同对象的成员函数时都是执行同一段函数代码,但是执行结果一般是不相同的。
- 不同的对象使用的是同一个函数代码段。它怎么能够分别对不同对象中的数据进行操作呢?原来C++为此专门设立了一个名为
this
的指针,用来指向不同的对象。(this
的使用看下一节类类型(2)) - 不论成员函数在类内定义还是在类外定义,成员函数的代码段都用同一种方式存储。
-
对象成员的引用
-
通过对象名和成员运算符访问对象中的成员;
对象名.成员名
。其中“.”
是成员运算符,用来对成员进行限定,指明所访问的是哪一个对象中的成员。 -
通过指向对象的指针访问对象中的成员;在
p
指向t
的前提下(t
是Time
类的对象),p->hour
,(*p).hour
和t.hour
三者等价。 -
通过对象的引用变量访问对象中的成员。
-
-
通过成员函数对数据成员进行操作称为类的实现
-
类中被操作的数据是私有的,实现的细节对用户是隐蔽的,这种实现称为**私有实现(private implementation)。**这种“类的公用接口与私有实现的分离”形成了信息隐蔽。
-
类声明和成员函数定义的分离
- 将类的声明(其中包含成员函数的声明)放在指定的头文件中,用户如果想用该类,只要把有关的头文件包含进来即可,不必在程序中重复书写类的声明。
- 头文件中包含了类的声明,因此在程序中就可以用该类来定义对象。由于在类体中包含了对成员函数的声明,在程序中就可以调用这些对象的公用成员函数。
- 为了实现所叙述的信息隐蔽,对类成员函数的定义一般不放在头文件中,而另外放在一个文件中。
//student.h (这是头文件,在此文件中进行类的声明)
class Student //类声明
{ public:
void display( ); //公用成员函数原型声明
private:
int num;
char name[20];
char sex;
};
//student.cpp //在此文件中进行函数的定义
#include <iostream>
#include ″student.h″ //不要漏写此行,否则编译通不过
void Student∷display( ) //在类外定义display类函数
{cout<<″num:″<<num<<endl;
cout<<″name:″<<name<<endl;
cout<<″sex:″<<sex<<endl;
}
//main.cpp 主函数模块
#include <iostream>
#include ″student.h″ //将类声明头文件包含进来
int main( )
{Student stud; //定义对象
stud.display( ); //执行stud对象的display函数
return 0;
}
包括3个文件的程序,组成两个文件模块: 一个是主模块main.cpp,一个是student.cpp。在主模块中又包含头文件student.h。在预编译时会将头文件student.h中的内容取代#include ″student.h″行
如果一个类声明多次被不同的程序所选用,每次都要对包含成员函数定义的源文件(如上面的student.cpp)进行编译,这是否可以改进呢?的确,可以不必每次都对它重复进行编译,而只需编译一次即可。把第一次编译后所形成的目标文件保存起来,以后在需要时把它调出来直接与程序的目标文件相连接即可。这和使用函数库中的函数是类似的。这也是把成员函数的定义不放在头文件中的一个好处。
在实际工作中,并不是将一个类声明做成一个头文件,而是将若干个常用的功能相近的类声明集中在一起,形成类库。
-
类库
- 是C++编译系统提供的标准类库;
- 用户根据自己的需要做成的用户类库,提供给自己和自己授权的人使用,这称为自定义类库。
-
类库包括两个组成部分:
- (1)类声明头文件;
- (2)已经过编译的成员函数的定义,它是目标文件。
-
用户只需把类库装入到自己的计算机系统中(一般装到C++编译系统所在的子目录下),并在程序中用#include命令行将有关的类声明的头文件包含到程序中,就可以使用这些类和其中的成员函数