类背后蕴涵的基本思想是数据抽象和封装。
(1) 数据抽象
数据抽象是一种依赖于接口和实现分离的编程(和设计)技术。类设计者必须关心类是如何实现的,但使用该类的程序员不必了解这些细节。相反,使用一个类型的程序员仅需了解类型的接口,他们可以抽象地考虑该类型做什么,而不必具体地考虑该类型如何工作。
(2) 封装
封装是一项低层次的元素组合起来的形成新的、高层次实体珠技术。函数是封装的一种形式:函数所执行的细节行为被封装在函数本身这个更大的实体中。被封装的元素隐藏了它们的实现细节——可以调用一个函数但不能访问它所执行的语句。同样地,类也是一个封装的实体:它代表若干成员的聚焦,大多数(良好设计的)类类型隐藏了实现该类型的成员。
(3)数据抽象和封装的好处
a.避免类内部出现无意的、可能破坏对象状态的用户级错误。
b.随时间推移可以根据需求改变或缺陷(bug)报告来完美类实现,而无须改变用户级代码。
关于类定义
(1)使用类型别名来简化类
除了定义数据和函数成员之外,类还可以定义自己的局部类型名字。如果为std::string::size_type 提供一个类型别名,那么 Screen 类将是一个更好的抽象:
的底层细节。定义index 来隐藏 Screen 的实现细节。将这个类型设为 public,就允许用户使用这个名字。
class Screen {
public:
// interface member functions
typedef std::string::size_type index;
private:
std::string contents;
index cursor;
index height, width;
};
类所定义的类型名遵循任何其他成员的标准访问控制。将index 的定义放在类的 public 部分,是因为希望用户使用这个名字。Screen 类的使用者不必了解用 string 实现
的底层细节。定义index 来隐藏 Screen 的实现细节。将这个类型设为 public,就允许用户使用这个名字。
(2)成员函数可被重载
重载操作符有特殊规则,是个例外,成员函数只能重载本类的其他成员函数。类的成员函数与普通的非成员函数以及在其他类中声明的函数不相关,也不能重载它们。重载的成员函数和普通函数应用相同的规则:两个重载成员的形参数量和类型不能完全相同。调用非成员重载函数所用到的函数匹配过程也应用于重载成员函数的调用。
(3)显式指定inline 成员函数
可以在类定义体内部指定一个成员为inline,作为其声明的一部分。或者,也可以在类定义外部的函数定义上指定inline。在声明和定义处指定inline 都是合法的。在类的外部定义inline 的一个好处是可以使得类比较容易阅读。
像其他inline 一样,inline 成员函数的定义必须在调用该函数的每个源文件中是可见的。不在类定义体内定义的 inline 成员函数,其定义通常应放在有类定义的同一头文件中。
(4)类声明与类定义
在一个给定的源文件中,一个类只能被定义一次。如果在多个文件中定义一个类,那么每个文件中的定义必须是完全相同的。
可以声明一个类而不定义它:
class Screen; // declaration of the Screen class
这个声明,有时称为前向声明(forward declaraton),在程序中引入了类类型的Screen。在声明之后、定义之前,类Screen 是一个不完全类型(incompetetype),即已知Screen 是一个类型,但不知道包含哪些成员。
不完全类型(incomplete type)只能以有限方式使用。不能定义该类型的对象。不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。
在创建类的对象之前,必须完整地定义该类。必须定义类,而不只是声明类,这样,编译器就会给类的对象预定相应的存储空间。同样地,在使用引用或指针访问类的成员之
前,必须已经定义类。
类的前向声明一般用来编写相互依赖的类。
(5)为类的成员使用类声明
只有当类定义已经在前面出现过,数据成员才能被指定为该类类型。如果该类型是不完全类型,那么数据成员只能是指向该类类型的指针或引用。因为只有当类定义体完成后才能定义类,因此类不能具有自身类型的数据成员。然而,只要类名一出现就可以认为该类已声明。因此,类的数据成员可以是指向自身类型的指针
或引用:
或引用:
class LinkScreen {
Screen window;
LinkScreen *next;
LinkScreen *prev;
};
(6)类对象
定义一个类时,也就是定义了一个类型。一旦定义了类,就可以定义该类型的对象。定义对象时,将为其分配存储空间,但(一般而言)定义类型时不进行存储分配。
(7)定义类类型的对象
定义了一个类类型之后,可以按以下两种方式使用。
a.将类的名字直接用作类型名。
b.指定关键字class 或 struct,后面跟着类的名字:
eg:
Sales_item item1; // default initialized object of type Sales_item
class Sales_item item1; // equivalent definition of item1
两种引用类类型方法是等价的。第二种方法是从 C 继承而来的,在 C++ 中仍然有效。第一种更为简练,由 C++ 语言引入,使得类类型更容易使用。