在之前的博客中,我们举了各种实例化对象的例子。但是,大家有没有思考过一个问题:如果我要实例化的对象是一个“群体”,比如,一个班的同学,或者一个球队的运动员,那应该怎么进行实例化呢?难道一个班有50个人,就要分别实例化50个对象吗?这显然是不现实的。在C++中,我们可以把他们实例化为一个对象数组,也就是“一组”对象。
今天就给大家分别介绍从栈中实例化对象数组和从堆中实例化对象数组,以及访问对象数组中每个元素的成员的方法。
首先,我们定义一个Teacher类,类中包括public修饰的构造函数、析构函数以及数据封装函数,private修饰的数据成员。然后我们来看一下怎么实例化对象数组。
#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类,为了减少篇幅,我这里就不展示函数定义的代码了。在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;
}
我们实例化了一个含有4个元素的对象数组。在这里,我们只对前两个对象元素进行赋值操作,然后用for循环打印出所有对象元素中的数据成员。
可以看到,对象数组中的4个元素的数据成员都被打印了出来,由于没有对t[2]和t[3]进行赋值操作,它们被赋予了系统默认值(字符串为空,整数为-858993460)。从构造函数和析构函数的调用情况来看,实例化了几个元素的对象数组,就会调用几次构造函数;运行结束时,也就会调用几次析构函数。
从堆中实例化数组对象,会比较复杂一些。接下来让我们看一下从堆中实例化对象数组的例子。我们将main函数改写成这样。
int main(void)
{
Teacher* p = new Teacher[3];
p->setName("Jack"); //第一个
p[0].setAge(25);
p++;
p->setName("Mary"); //第二个
p[0].setAge(21);
p[1].setName("Paul"); //第三个
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;
}
我们从堆中实例化了一个对象指针p,让它指向了一个对象数组而非一个单一的对象。那么如何对对象元素进行访问呢?原理是利用指针p的移动。在C语言中,我们知道指针指向数组的地址就是数组中第一个元素的地址,在C++中也是如此。如果直接用p指向的对象元素的setName函数,就是指向第一个元素的setName函数;同样,我们不用指针符号,也可以用p[0].setName,效果是完全一样的。如果要访问第二个元素,可以让指针p向后移一位,也就是p++,然后再指向元素中的函数;也可以直接用p[1].函数名这样的形式。但是值得一提的是,如果指针向后移动了一位,那么这时候p->函数名指向的不再是第一个对象元素的函数,而是第二个,同理p[0]也指向的是第二个元素,p[1]也就指向了第三个元素。如上面的代码所示,这样就可以完成全部三个对象元素的赋值。
那么,如何将这三个对象元素的数据成员打印出来呢?这也是一个问题,因为在我上面赋值部分的代码结束之后,p是指向该对象数组的最后一个元素的,我们不能通过for循环直接用p[i]的形式来打印。于是,我们可以直接倒序打印。先打印最后一个对象元素中的数据成员,然后指针向前移动一位,使它指向倒数第二个对象元素,再进行打印......如此循环三次,就可以打印出所有对象元素的数据成员。
注意到代码中,for循环结束后,还多写了一句"p++;",可能有人不知道这一步是干什么用的,觉得多此一举。其实不然,我们可以仔细想一下,循环结束时,p指向了哪里?它是指向第一个元素的吗?答案是否定的,由于在之前我们只对p进行了两次p++,而在for循环中我们进行了三次p--,于是p这时候就指向了一个非法的位置。很显然,我们不能去释放一段根本就没有分配给我们的内存。所以,需要再进行"p++",使p重新指回对象数组的首元素,然后才能进行释放空间的操作。在释放时,要注意p指向的是数组,delete后要加上中括号。
最后看一下运行的结果。
可以看到调用了三次构造函数和三次析构函数,并且析构函数在程序运行结束之前被调用。
以上就是有关对象数组的内容,下一篇:对象成员。