在之前的博客中,我們舉了各種實(shí)例化對象的例子。但是,大家有沒有思考過一個(gè)問題:如果我要實(shí)例化的對象是一個(gè)“群體”,比如,一個(gè)班的同學(xué),或者一個(gè)球隊(duì)的運(yùn)動(dòng)員,那應(yīng)該怎么進(jìn)行實(shí)例化呢?難道一個(gè)班有50個(gè)人,就要分別實(shí)例化50個(gè)對象嗎?這顯然是不現(xiàn)實(shí)的。在C++中,我們可以把他們實(shí)例化為一個(gè)對象數(shù)組,也就是“一組”對象。
今天就給大家分別介紹從棧中實(shí)例化對象數(shù)組和從堆中實(shí)例化對象數(shù)組,以及訪問對象數(shù)組中每個(gè)元素的成員的方法。
首先,我們定義一個(gè)Teacher類,類中包括public修飾的構(gòu)造函數(shù)、析構(gòu)函數(shù)以及數(shù)據(jù)封裝函數(shù),private修飾的數(shù)據(jù)成員。然后我們來看一下怎么實(shí)例化對象數(shù)組。
#pragma once
#include <string>
using namespace std;
class Teacher
{
public:
Teacher();
~Teacher();
void setName(string _name);
string getName();
void setAge(int _age);
int getAge();
private:
string m_strName;
int m_iAge;
};
我們在頭文件Teacher.h中定義了Teacher類,為了減少篇幅,我這里就不展示函數(shù)定義的代碼了。在demo.cpp中。
#include <iostream>
#include <string>
#include "Teacher.h"
using namespace std;
int main(void)
{
Teacher t[4];
t[0].setName("Jack");
t[0].setAge(25);
t[1].setName("Mary");
t[1].setAge(21);
for (int i = 0; i < 4; i++)
{
cout << t[i].getName() << " " << t[i].getAge() << endl;
}
system("PAUSE");
return EXIT_SUCCESS;
}
我們實(shí)例化了一個(gè)含有4個(gè)元素的對象數(shù)組。在這里,我們只對前兩個(gè)對象元素進(jìn)行賦值操作,然后用for循環(huán)打印出所有對象元素中的數(shù)據(jù)成員。

可以看到,對象數(shù)組中的4個(gè)元素的數(shù)據(jù)成員都被打印了出來,由于沒有對t[2]和t[3]進(jìn)行賦值操作,它們被賦予了系統(tǒng)默認(rèn)值(字符串為空,整數(shù)為-858993460)。從構(gòu)造函數(shù)和析構(gòu)函數(shù)的調(diào)用情況來看,實(shí)例化了幾個(gè)元素的對象數(shù)組,就會(huì)調(diào)用幾次構(gòu)造函數(shù);運(yùn)行結(jié)束時(shí),也就會(huì)調(diào)用幾次析構(gòu)函數(shù)。
從堆中實(shí)例化數(shù)組對象,會(huì)比較復(fù)雜一些。接下來讓我們看一下從堆中實(shí)例化對象數(shù)組的例子。我們將main函數(shù)改寫成這樣。
int main(void)
{
Teacher* p = new Teacher[3];
p->setName("Jack"); //第一個(gè)
p[0].setAge(25);
p++;
p->setName("Mary"); //第二個(gè)
p[0].setAge(21);
p[1].setName("Paul"); //第三個(gè)
p++;
p->setAge(30);
for (int i = 0; i < 3; i++)
{
cout << p->getName() << " " << p->getAge() << endl;
p--;
}
p++;
delete[]p;
p = NULL;
system("PAUSE");
return EXIT_SUCCESS;
}
我們從堆中實(shí)例化了一個(gè)對象指針p,讓它指向了一個(gè)對象數(shù)組而非一個(gè)單一的對象。那么如何對對象元素進(jìn)行訪問呢?原理是利用指針p的移動(dòng)。在C語言中,我們知道指針指向數(shù)組的地址就是數(shù)組中第一個(gè)元素的地址,在C++中也是如此。如果直接用p指向的對象元素的setName函數(shù),就是指向第一個(gè)元素的setName函數(shù);同樣,我們不用指針符號,也可以用p[0].setName,效果是完全一樣的。如果要訪問第二個(gè)元素,可以讓指針p向后移一位,也就是p++,然后再指向元素中的函數(shù);也可以直接用p[1].函數(shù)名這樣的形式。但是值得一提的是,如果指針向后移動(dòng)了一位,那么這時(shí)候p->函數(shù)名指向的不再是第一個(gè)對象元素的函數(shù),而是第二個(gè),同理p[0]也指向的是第二個(gè)元素,p[1]也就指向了第三個(gè)元素。如上面的代碼所示,這樣就可以完成全部三個(gè)對象元素的賦值。
那么,如何將這三個(gè)對象元素的數(shù)據(jù)成員打印出來呢?這也是一個(gè)問題,因?yàn)樵谖疑厦尜x值部分的代碼結(jié)束之后,p是指向該對象數(shù)組的最后一個(gè)元素的,我們不能通過for循環(huán)直接用p[i]的形式來打印。于是,我們可以直接倒序打印。先打印最后一個(gè)對象元素中的數(shù)據(jù)成員,然后指針向前移動(dòng)一位,使它指向倒數(shù)第二個(gè)對象元素,再進(jìn)行打印......如此循環(huán)三次,就可以打印出所有對象元素的數(shù)據(jù)成員。
注意到代碼中,for循環(huán)結(jié)束后,還多寫了一句"p++;",可能有人不知道這一步是干什么用的,覺得多此一舉。其實(shí)不然,我們可以仔細(xì)想一下,循環(huán)結(jié)束時(shí),p指向了哪里?它是指向第一個(gè)元素的嗎?答案是否定的,由于在之前我們只對p進(jìn)行了兩次p++,而在for循環(huán)中我們進(jìn)行了三次p--,于是p這時(shí)候就指向了一個(gè)非法的位置。很顯然,我們不能去釋放一段根本就沒有分配給我們的內(nèi)存。所以,需要再進(jìn)行"p++",使p重新指回對象數(shù)組的首元素,然后才能進(jìn)行釋放空間的操作。在釋放時(shí),要注意p指向的是數(shù)組,delete后要加上中括號。
最后看一下運(yùn)行的結(jié)果。

可以看到調(diào)用了三次構(gòu)造函數(shù)和三次析構(gòu)函數(shù),并且析構(gòu)函數(shù)在程序運(yùn)行結(jié)束之前被調(diào)用。
以上就是有關(guān)對象數(shù)組的內(nèi)容,下一篇:對象成員。