C++物件陣列(詳解版)

2020-07-16 10:04:41
到目前為止,我們所了解的是,陣列中的所有元素必須是相同的資料型別,並且所使用的陣列也只是具有一些簡單的資料型別,如 int 陣列和 string 陣列。

陣列其實也可以容納更複雜的資料型別,比如程式設計師定義的結構或物件。這一切所需的條件就是,每個元素都擁有相同型別的結構或同一類的物件。

現在來看一看物件陣列。程式設計師可以像定義任何陣列一樣定義一個物件陣列。例如,如果已經定義了一個名為 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 個關鍵點:
  1. 陣列的元素可以是物件。
  2. 如果在建立物件陣列時未使用初始化列表,則會為陣列中的每個物件呼叫預設建構函式。
  3. 沒有必要讓陣列中的所有物件都使用相同的建構函式。
  4. 如果在建立物件陣列時使用初始化列表,則將根據所使用引數的數量和型別為每個物件呼叫正確的建構函式。
  5. 如果建構函式需要多個引數,則初始化項必須釆用建構函式呼叫的形式。
  6. 如果列表中的初始化項呼叫少於陣列中的物件,則將為所有剩餘的物件呼叫預設建構函式。
  7. 最好總是提供一個預設的建構函式。如果沒有,則必須確保為陣列中的每個物件提供一個初始化項。