一、类对象数组
类的对象和C++其他数据类型一样,也可以为其建立数组,数组的表示方法和结构一样。

#include iostream.h 


class Date 

{ 

int mo,da,yr; 

public: 

Date(int m=0,int d=0, int y=0) { mo=m; da=d; yr=y;} 

void display() const { cout<<mo<<' '<<da<<'="" '<<yr<<endl;="" } 

  }; 


 int main() 

 { 

 Date dates[2]; 

 Date today(12,31,2003); 

 dates[0]=today; 

 dates[0].display(); 

 dates[1].display(); 


 return 0; 

 } 


 1.类对象数组和默认构造函数 

 在前面已经说过,不带参数或者所有参数都有默认值的构造函数叫做默认构造函数。如果类中没有构造函数,编译器会自动提供一个什么都不做的公共默认构造函数 。如果类当中至少有一个构造函数,编译器就不会提供默认构造函数。 

 如果类当中不含默认构造函数,则无法实例化其对象数组。因为实例花类对象数组的格式不允许用初始化值来匹配某个构造函数的参数表。 

 上面的程序中,main()函数声明了一个长度为2的Date对象数组,还有一个包含初始化值的单个Date对象。接着把这个初始化的Date对象赋值给数组中第一个对象,然后显示两个数组元素中包含的日期。从输出中可以看到,第一个日期是有效日期,而第二个显示的都是0。 

 当声明了某个类的对象数组时,编译器会为每个元素都调用默认构造函数。 

 下面的程序去掉了构造函数的默认参数值,并且增加了一个默认构造函数。 


 #include  


 class Date 

 { 

 int mo, da, yr; 

 public: 

 Date(); 

 Date(int m,int d,int y) { mo=m; da=d; yr=y;} 

 void display() const { cout <<mo<<' '<<da<<'="" '<<yr<<endl;="" } 

  }; 


 Date::Date() 

 { 

 cout <<date constructor="" running<<endl; 

  mo=0; da=0; yr=0; 

 } 


 int main() 

 { 

 Date dates[2]; 

 Date today(12,31,2003); 

 dates[0]=today; 

 dates[0].display(); 

 dates[1].display(); 


 return 0; 

 } 

 运行程序,输出为: 

 Date constructor running 

 Date constructor running 

 12/31/2003 

 0/0/0 


 从输出中可以看出,Date()这个默认构造函数被调用了两次。 

 2.类对象数组和析构函数 

 当类对象离开作用域时,编译器会为每个对象数组元素调用析构函数。 


 #include iostream.h 


 class Date 

 { 

 int mo,da,yr; 

 public: 

 Date(int m=0,int d=0,int y=0) { mo=m; da=d; yr=y;} 

 ~Date() {cout<<date destructor="" running<<endl;} 

  void display() const {cout<<mo<<' '<<da<<'="" '<<yr<<endl;="" } 

  }; 


 int main() 

 { 

 Date dates[2]; 

 Date today(12,31,2003); 

 dates[0]=today; 

 dates[0].display(); 

 dates[1].display(); 


 return 0; 

 } 

 运行程序,输出为: 

 12/31/2003 

 0/0/0 

 Date destructor running 

 Date destructor running 

 Date destructor running 


 表明析构函数被调用了三次,也就是dates[0],dates[1],today这三个对象离开作用域时调用的。 


 二、静态成员 

 可以把类的成员声明为静态的。静态成员只能存在唯一的实例。所有的成员函数都可以访问这个静态成员。即使没有声明类的任何实例,静态成员也已经是存在的。不过类当中声明静态成员时并不能自动定义这个变量,必须在类定义之外来定义该成员。 

 1.静态数据成员 

 静态数据成员相当于一个全局变量,类的所有实例都可以使用它。成员函数能访问并且修改这个值。如果这个静态成员是公有的,那么类的作用域之内的所有代码(不论是在类的内部还是外部)都可以访问这个成员。下面的程序通过静态数据成员来记录链表首项和末项的地址。 


 #include iostream.h 

 #include string.h 


 class ListEntry 

 { 

 public: 

 static ListEntry* firstentry; 

 private: 

 static ListEntry* lastentry; 

 char* listvalue; 

 ListEntry* nextentry; 

 public: 

 ListEntry(char*); 

 ~ListEntry() { delete [] listvalue;} 

 ListEntry* NextEntry() const { return nextentry; }; 

 void display() const { cout<<listvalue<<endl; } 

  }; 


 ListEntry* ListEntry::firstentry; 

 ListEntry* ListEntry::lastentry; 


 ListEntry::ListEntry(char* s) 

 { 

 if(firstentry==0) firstentry=this; 

 if(lastentry!=0) lastentry->nextentry=this; 

 lastentry=this; 

 listvalue=new char[strlen(s)+1]; 

 strcpy(listvalue,s); 

 nextentry=0; 

 } 


 int main() 

 { 

 while (1) 

 { 

 cout<<\nEnter a name ('end' when done): ; 

 char name[25]; 

 cin>>name; 

 if(strncmp(name,end,3)==0) break; 

 new ListEntry(name); 

 } 

 ListEntry* next = ListEntry::firstentry; 

 while (next != 0) 

 { 

 next->display(); 

 ListEntry* hold = next; 

 next=next->NextEntry(); 

 delete hold; 

 } 

 return 0; 

 } 


 程序首先显示提示信息,输入一串姓名,以end作为结束标志。然后按照输入顺序来显示姓名。构造函数将表项加入链表,用new运算符来声明一个表项,但并没有把new运算符返回的地址赋值给某个指针,这是因为构造函数会把该表项的地址赋值给前一个表项的nextentry指针。 

 这个程序和前面将的逆序输出的程序都不是最佳方法,最好的方法是使用类模板,这在后面再介绍。 

 main()函数取得ListEntry::firstentry的值,开始遍历链表,因此必需把ListEntry::firstentry设置成公有数据成员,这不符合面向对象程序的约定,因为这里数据成员是公有的。 

 2.静态成员函数 

 成员函数也可以是静态的。如果一个静态成员函数不需要访问类的任何实例的成员,可以使用类名或者对象名来调用它。静态成员通常用在只需要访问静态数据成员的情况下。 

 静态成员函数没有this指针,因为它不能访问非静态成员,所以它们不能把this指针指向任何东西。 

 下面的程序中,ListEntry类中加入了一个静态成员函数FirstEntry(),它从数据成员firstentry获得链表第一项的地址,在这儿,firstentry已经声明为私有数据成员了。 


 #include iostream.h 

 #include string.h 


 class ListEntry 

 { 

 static ListEntry* firstentry; 

 static ListEntry* lastentry; 

 char* listvalue; 

 ListEntry* nextentry; 

 public: 

 ListEntry(char*); 

 ~ListEntry() { delete [] listvalue;} 

 static ListEntry* FirstEntry() { return firstentry; } 

 ListEntry* NextEntry() const { return nextentry; }; 

 void display() const { cout<<listvalue<<endl; } 

  }; 


 ListEntry* ListEntry::firstentry; 

 ListEntry* ListEntry::lastentry; 


 ListEntry::ListEntry(char* s) 

 { 

 if(firstentry==0) firstentry=this; 

 if(lastentry!=0) lastentry->nextentry=this; 

 lastentry=this; 

 listvalue=new char[strlen(s)+1]; 

 strcpy(listvalue, s); 

 nextentry = 0; 

 } 


 int main() 

 { 

 while (1) 

 { 

 cout<<\nEnter a name ('end' when done):; 

 char name[25]; 

 cin >> name; 

 if(strncmp(name,end,3)==0) break; 

 new ListEntry(name); 

 } 

 ListEntry* next = ListEntry::FirstEntry(); 

 while (next != 0) 

 { 

 next->display(); 

 ListEntry* hold = next; 

 next = next->NextEntry(); 

 delete hold; 

 } 

 return 0; 

 }


函数ListEntry::FirstEntry()是静态的,返回静态数据成员firstentry的值。
3.公有静态成员
如果一个静态成员象上面程序一样是公有的,那么在整个程序中都可以访问它。可以在任何地方调用公有景泰成员函数,而且不需要有类的实例存在。但公有静态成员函数不完全是全局的,它不仅仅存在于定义类的作用域内。在这个作用域里面,只要在函数名前加上类名和域解析运算符::就可以调用该函数。