C++学习笔记----7、使用类与对象获得高性能(一)---- 书写类(1)
1、表格处理程序示例
表格处理程序是一个二维的“细胞”网格,每个格子包含了一个数字或者字符串。专业的表格处理程序比如微软的Excel提供了执行数学运算的能力,比如计算格子中的值的和。表格处理程序示例无意挑战微软的市场地位,但是对于演示类与对象还是很有帮助的。
表格处理程序使用了两个基础的类:Spreadsheet与SpreadsheetCell。每个Spreadsheet对象包含了SpreadsheetCell对象。还有,SpreadsheetApplication类管理Spreadsheet集合。
这里展示了SpreadsheetCell的不同版本,是为了逐步地介绍相关概念。这样的话,不同的对类的尝试并不总是给出了写出该类的每个特点的最好方式。需要特别指出的是,前面的例子省略了重要的属性,该属性通常应该被包含,但是清空没有介绍到。在本章的一开始你就可以下载其最终版本。
2、书写类
当你写一个类时,要指定其行为,或者叫做成员函数,会应用于该类的对象,指定属性,或者叫做成员变量,每一个对象都应该包含的。
在书写类的过程中有两个部件 :定义类本身与定义其成员函数。
2.1、类定义
首先我们尝试一个简单的SpreadsheetCell类在spreadsheet_cell模块中,每一个格子只包含一个单独的数字:
export module spreadsheet_cell;
export class SpreadsheetCell
{
public:
void setValue(double value);
double getValue() const;
private:
double m_value{ 0 };
};
第一行指出这是一个叫做spreadsheet_cell的模块的定义。每一类的定义都是以class关键字开始后接类的名字。如果类定义在一个模块中,该类一定要import进来才可见,定义时一定要在class关键字之前加上export。类的定义就是声明并且以分号结束。
类的定义通常在一个其名字的文件中。例如,SpreadsheetCell类定义在一个叫做SpreadsheetCell.cppm的文件中。有些编译器要求使用特定的扩展名;有些则不要求。
2.1.1、类成员
类可以有多个成员。成员可以是成员函数(顺序为函数,构造函数,析构函数),成员变量(也叫做数据成员),成员枚举,类型别名,嵌套类,等等。
这两行看起来像函数原型的声明了类支持的成员函数:
void setValue(double value);
double getValue() const;
用const声明一个不改变对象的成员函数总是一个不错的主意,就像getValue()成员函数。
看起来像是一个变量声明的这一行声明了类的成员变量:
double m_value{ 0 };
类定义了应用的成员函数与数据成员。它们只应用于类的特定的实例,那就是对象。有一个例外就是静态成员,这个我们以后再讨论。类定义了概念;对象包含了实际的数据位。这样的话,每个对象包含了m_value数据成员的值。成员函数实现在所有对象之间共享。类可以包含任意数量的成员函数与数据成员。数据成员与成员函数不能重名。
2.1.2、访问控制
类中的每个成员都有三个访问说明符的一个:public,private,或者protected。protected访问说明符以后再解释。访问说明符应用于声明后面的所有的成员,直到下一个访问说明符。在SpreadsheetCell类中,setValue()与getValue()成员函数具有public访问权限,而m_value数据成员具有private访问权限。
类的缺省的访问说明符为private:所有的第一个访问说明符之前的成员声明都具有private访问权限。例如,把public访问说明符移到setValue()成员函数声明之后,setValue()成员函数就不是public访问权限而是private访问权限了。
export class SpreadsheetCell
{
void setValue(double value);
public:
double getValue() const;
private:
double m_value{ 0 };
};
在C++中,struct可以像class一样拥有成员函数。实际上,只有一个不同,struct的缺省访问说明符为public,而class的缺省访问说明符是private。
例如,SpreadsheetCell类可以用struct重写如下:
export struct SpreadsheetCell
{
void setValue(double value);
double getValue() const;
private:
double m_value;
};
然而,这样做是非常不方便的。struct通常用于只需要公共访问的数据成员集合时,并且没有成员函数。下面的例子就是一个简单的struct来保存2-D的点坐标:
export struct Point
{
double x;
double y;
};
2.1.3、声明顺序
声明成员与访问说明符可以用任何顺序:c++没有任何限制,比如成员函数要在数据成员前面,或者public要在private前面。还有,访问说明符可以重复。例如,SpreadsheetCell定义可以看起来像这样:
export class SpreadsheetCell
{
public:
void setValue(double value);
private:
double m_value;
public:
double getValue() const;
};
然而,语法是语法,美观易读也是我们写出优雅程序的追求。为了清晰,将基于访问说明符的声明进行分组,在这些声明中,对成员函数与数据成员进行分组,都不失为一个好主意。
2.1.4、类内成员初始化
数据成员可以在类定义时直接初始化。例如,SpreadsheetCell类可以缺省在类定义时直接初始化m_value为0,如下:
export class SpreadsheetCell
{
// Remainder of the class definition omitted for brevity
private:
double m_value{ 0 };
};
总是推荐要对类的数据成员进行初始化。