数组其实也可以容纳更复杂的数据类型,比如程序员定义的结构或对象。这一切所需的条件就是,每个元素都拥有相同类型的结构或同一类的对象。
现在来看一看对象数组。程序员可以像定义任何数组一样定义一个对象数组。例如,如果已经定义了一个名为 Circle 的类,那么就可以使用以下语句创建一个可以容纳 4 个 Circle 对象的数组:
Circle circle[4];
这 4 个对象是 circle[0]、circle[l]、circle[2] 和 circle[3]。
请注意,类的名称是 Circle,其首字母 C 是大写的,数组的名称是 circle,其首字母 c 是小写的。我们有过约定,类的名称首字母使用大写,变量或者对象的名称首字母则釆用小写。为对象数组中某个对象调用类函数就像为任何其他对象调用类函数一样,区别在于必须包含下标,以标识数组中的哪个对象被引用。
例如,以下语句将调用 circle[2] 的 findArea 函数:
circle[2].findArea();
下面的程序通过创建和使用 Circle 类对象数组来演示了上述操作。以下是它使用的 Circle 类的定义:
// Thisheader file contains the Circle class declaration. #ifndef CIRCLE_H #define CIRCLE_H #include <cmath> class Circle { private: double radius; // Circle radius int centerX, centerY; // Center coordinates public: Circle() // Default constructor { // accepts no arguments radius = 1.0; centerX = centerY = 0; } Circle(double r) // Constructor 2 { // accepts 1 argument radius = r; centerX = centerY = 0; } Circle(double r, int x, int y) // Constructor 3 { // accepts 3 arguments radius = r; centerX = x; centerY = y; } void setRadius(double r) { radius = r; } int getXcoord() { return centerX; } int getYcoord() { return centerY; } double findArea() { return 3.14 * pow(radius, 2); } }; // End Circle class declaration #endif
在接下来的程序中,需要特别注意其关键部分,在第 5 行中包含了 Circle.h 头文件,在该文件中包含了 Circle 类定义。然后是在第 11 行中,创建了一个由 4 个 Circle 对象组成的数组。在第 13〜19 行中的循环为每个对象调用 setRadius 方法。在第 23〜26 行使用第 2 个循环为每个对象调用 findArea 方法并显示结果。
// This program uses an array of objects. // The objects are instances of the Circle class. #include <iostream> #include <iomanip> #include "Circle.h" // Circle class declaration file using namespace std; const int NUM_CIRCLES = 4; int main() { Circle circle[NUM_CIRCLES]; // Define an array of Circle objects // Use'a loop to initialize the radius of each object for (int index = 0; index < NUM_CIRCLES; index++) { double r; cout << "Enter the radius for circle " << (index+1) <<":"; cin >> r; circle[index].setRadius(r); } // Use a loop to get and print out the area of each object cout << fixed << showpoint << setprecision(2); cout << "/nHere are the areas of the " << NUM_CIRCLES << "circles . /n"; for (int index = 0; index < NUM_CIRCLES; index++) { cout << "circle " << (index+1) << setw (8) << circle[index].findArea() << endl; } return 0; }
程序输出结果:
Enter the radius for circle 1:0
Enter the radius for circle 2:2
Enter the radius for circle 3:2.5
Enter the radius for circle 4:10
Here are the areas of the 4circles .
circle 1 0.00
circle 2 12.56
circle 3 19.62
circle 4 314.00
注意,每当使用一个没有参数的构造函数创建对象数组时,如果存在默认构造函数,则它将为数组中的每个对象运行,此程序就是这样。
当 Circle 对象的数组首先被创建时,为数组中的每个对象执行默认构造函数,并为其半径赋值 1.0,但是这种情况并没有发生,这是因为每个对象对 setRadius 成员函数的调用在起作用,它们都使用传递给 setRadius 的新值替换了默认的 1.0。
如果我们将上边程序的第 13〜19 行注释掉,那么就不会有 setRadius 的调用。因此,当第 23〜26 行的循环获取并打印圆面积时,数组中的每个对象的半径仍将为 1.0。其输出结果将如下所示:
Here are the areas of the 4 circles.
circle1 3.14
circle2 3.14
circle3 3.14
circle4 3.14
也可以创建一个对象数组,并为每个对象调用另一个构造函数。为此则必须使用初始化列表。以下数组定义和初始化列表将创建 4 个 Circle 对象,并将它们初始化为在上边程序样本运行中输入的相同的 4 个值。
circle[NUM_CIRCLES] = {0.0, 2.0, 2.5, 10.0};
这将调用构造函数接受一个 double 参数,并设置以下半径值:
对象 | 半径 |
---|---|
circle[0] | 0.0 |
circle[1] | 2.0 |
circle[2] | 2.5 |
circle[3] | 10.0 |
如果初始化列表的长度小于对象的数量,则任何剩余的对象都将由默认构造函数初始化。例如,以下语句调用构造函数,该构造函数为前 3 个对象接收一个 double 参数,并使默认构造函数为第 4 个对象运行。第 4 个对象的默认半径为 1.0。
circle[NUM_CIRCLES] = {0.0, 2.0, 2.5};
在下面程序中有该用法演示:
// This program demonstrates how an overloaded constructor // that accepts an argument can be invoked for multiple objects //when an array of objects is created. #include <iostream> #include <iomanip> #include "Circle.h" // Circle class declaration file using namespace std; const int NUM_CIRCLES = 4; int main() { // Define an array of 4 Circle objects. Use an initialization list // to call the 1-argument constructor for the first 3 objects. // The default constructor will be called for the final object. Circle circle[NUM_CIRCLES] = {0.0, 2.0, 2.5}; // Display the area of each object cout << fixed << showpoint << setprecision (2); cout << "Here are the areas of the " << NUM_CIRCLES << " circles . /n"; for (int index = 0; index < NUM_CIRCLES; index++) { cout << "circle " << (index+1) << setw (8) << circle[index].findArea() << endl; } return 0; }
程序输出结果:
Here are the areas of the 4 circles .
circle 1 0.00
circle 2 12.56
circle 3 19.62
circle 4 3.14
要使用需要多个参数的构造函数,则初始化项必须釆用函数调用的形式。例如,来看下面的定义语句,它为 3 个 Circle 对象的每一个调用 3 个参数的构造函数:
Circle circle[3] = {Circle(4.0, 2, 1),Circle(2.0, 1, 3),Circle (2.5, 5, -1) };
circle[0] 的 radius 变量设置为 4.0,centerX 变量设置为 2,centerY 变量设置为 1;circle[1] 的 radius 变量设置为 2.0,centerX 变量设置为 1,centerY 变量设置为 3;circle[2] 的 radius 变量设置为 2.5,centerX 变量设置为 5,centerY 变量设置为 -1。
没有必要为数组中的每个对象调用相同的构造函数。例如,以下语句也是合法的:
Circle circle [3] = { 4.0,Circle (2.0, 1, 3),2.5 };
该语句为 circle[0] 和 circle[2] 调用 1 参数构造函数,而为 circle[1] 调用的则是 3 参数构造函数。
总而言之,要记住关于对象数组的 7 个关键点:
- 数组的元素可以是对象。
- 如果在创建对象数组时未使用初始化列表,则会为数组中的每个对象调用默认构造函数。
- 没有必要让数组中的所有对象都使用相同的构造函数。
- 如果在创建对象数组时使用初始化列表,则将根据所使用参数的数量和类型为每个对象调用正确的构造函数。
- 如果构造函数需要多个参数,则初始化项必须釆用构造函数调用的形式。
- 如果列表中的初始化项调用少于数组中的对象,则将为所有剩余的对象调用默认构造函数。
- 最好总是提供一个默认的构造函数。如果没有,则必须确保为数组中的每个对象提供一个初始化项。
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/22090.html