16、对象数组,对象指针,常对象、对象的常引用

1、对象数组

Student stud[50]; //假设已声明了Student类,定义stud数组,有50个元素

在建立数组时,同样要调用构造函数。如果有50个元素,需要调用50次构造函数。在定义对象数组时应当怎样实现初始化呢?在花括号中分别写出构造函数并指定实参。如果构造函数有3个参数,分别代表学号、年龄、成绩。则可以这样定义对象数组: 

Student Stud[3]={     //定义对象数组

Student(1001,18,87),  //调用第1个元素的构造函数,为它提供3个实参

Student(1002,19,76),  //调用第2个元素的构造函数,为它提供3个实参

Student(1003,18,72)  //调用第3个元素的构造函数,为它提供3个实参

                };

2、对象指针

1)指向对象的指针

对象空间的起始地址就是对象的指针。可以定义一个指针变量,用来存放对象的指针。

Time *pt;                  //定义pt为指向Time类对象的指针变量

Time t1;                   //定义t1为Time类对象

pt=&t1;                    //将t1的起始地址赋给pt

定义指向类对象的指针变量的一般形式为 

类名 *对象指针名;

*pt               pt所指向的对象,即t1。

(*pt).hour         pt所指向的对象中的hour成员,即t1.hour

pt->hour          pt所指向的对象中的hour成员,即t1.hour

(*pt).get_time ( )   调用pt所指向的对象中的get_time函数,即t1.get_time

pt->get_time ( )  调用pt所指向的对象中的get_time函数,即t1.get_time

2)指向对象成员的指针

存放对象成员地址的指针变量就是指向对象成员的指针变量。

定义指向对象数据成员的指针变量的一般形式为

数据类型名 *指针变量名;

int *p1;       //定义指向整型数据的指针变量

p1=&t1.hour; //将对象t1的数据成员hour的地址赋给p1,p1指向t1.hour

定义指向成员函数的指针变量应该采用下面的形式: 

void (Time∷*p2)( );  //定义p2为指向Time类中公用成员函数的指针变量

定义指向公用成员函数的指针变量的一般形式为 

数据类型名 (类名∷*指针变量名)(参数表列);

    指针变量的类型必须与赋值号右侧函数的类型相匹配,要求在以下3方面都要匹配: ①函数参数的类型和参数个数;②函数返回值的类型;③所属的类。

使指针变量指向一个公用成员函数的一般形式为 

指针变量名=&类名∷成员函数名;

p2=&Time∷get_time;

再如:

void (Time∷*p3)( );     //定义指向Time类公用成员函数的指针变量p3

p3=&Time∷get_time;  //使p3指向Time类公用成员函数get_time

(t1.*p3)( );  //调用对象t1中p3所指的成员函数(即t1.get_time( ))

void (Time∷*p3)( )=&Time∷get_time;   //定义指针变量时指定其指向

成员函数的入口地址的正确写法是: &类名∷成员函数名。

#include <iostream>

using namespace std;

class Time

{

public:

 Time(int,int,int);

 int hour;

 int minute;

 int sec;

 void get_time();

};

Time::Time(int h,int m,int s)

{

hour=h;

minute=m;

sec=s;

}

void Time::get_time()

{

cout<<hour<<":"<<minute<<":"<<sec<<endl;

}

int main()

{

Time t1(10,13,56);

int *p1=&t1.hour;

cout<<*p1<<endl;

t1.get_time();

Time *p2=&t1;

p2->get_time();

void (Time::*p3)();

p3=&Time::get_time;

(t1.*p3)();

}

3)this指针

在每一个成员函数中都包含一个特殊的指针,称为this。它是指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址。

(this->height)*(this->width)*(this->length)

如果当前this指向a对象,因此相当于执行: (a.height)*(a.width)*(a.length)

this指针是隐式使用的。

int Box∷volume( )

{return (height*width*length);      

}

C++把它处理为

int Box∷volume(Box *this)

{return(this->height * this->width * this->length);      

}

return(height * width * length);   //隐含使用this指针

return(this->height * this->width * this->length); //显式使用this指针    

3、共用数据的保护

1)常对象

在定义对象时指定对象为常对象。常对象必须要有初值,如

Time const t1(12,34,46);                   //t1是常对象

    这样,在所有的场合中,对象t1中的所有成员的值都不能被修改。凡希望保证数据成员不被改变的对象,可以声明为常对象。

定义常对象的一般形式为

类名 const 对象名[(实参表列)];

也可以把const写在最左面: 

const 类名 对象名[(实参表列)];

二者等价。

    如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数(除了由系统自动调用的隐式的构造函数和析构函数)。引用常对象中的数据成员,需将该成员函数声明为const。

    void get_time( ) const;         //将函数声明为const

    常成员函数可以访问常对象中的数据成员,但仍然不允许修改常对象中数据成员的值。但如果将数据成员声明为mutable,如 

mutable int count;

把count声明为可变的数据成员,这样就可以用声明为const的成员函数来修改它的值。

2)常对象成员

a、常数据成员

       常数据成员的值是不能改变的,只能通过构造函数的参数初始化表对常数据成员进行初始化,且在定义时必须初始化。如在类体中定义了常数据成员hour:

const int hour=12;          //声明hour为常数据成员

不能采用在构造函数中对常数据成员赋初值的方法。

在类外定义构造函数,应写成以下形式: 

Time∷Time(int h):hour(h){} //通过参数初始化表对常数据成员hour初始化

常对象的数据成员都是常数据成员,因此常对象的构造函数只能用参数初始化表对常数据成员进行初始化。

b、常成员函数

    如果将成员函数声明为常成员函数,则只能引用本类中的数据成员,而不能修改它们,如只用于输出数据等。如 

void get_time( ) const;           //注意const的位置在函数名和括号之后

    const是函数类型的一部分,在声明函数和定义函数时都要有const关键字,在调用时不必加const。常成员函数可以引用const数据成员,也可以引用非const的数据成员。const数据成员可以被const成员函数引用,也可以被非const的成员函数引用。

    如果已定义了一个常对象,只能调用其中的const成员函数,而不能调用非const成员函数(不论这些函数是否会修改对象中的数据)。如果需要访问对象中的数据成员,可将常对象中所有成员函数都声明为const成员函数,但应确保在函数中不修改对象中的数据成员。常对象只保证其数据成员是常数据成员,其值不被修改。如果在常对象中的成员函数未加const声明,编译系统把它作为非const成员函数处理。常成员函数不能调用另一个非const成员函数。

c、常指针    

将指针变量声明为const型,这样指针值始终保持为其初值,不能改变。如

Time t1(10,12,15),t2;  //定义对象

Time * const ptr1;    //const位置在指针变量名前面,规定ptr1的值是常值

ptr1=&t1;           //ptr1指向对象t1,此后不能再改变指向

定义指向对象的常指针的一般形式为

类名 * const 指针变量名;

也可以在定义指针变量时使之初始化,如

Time * const ptr1=&t1;             //指定ptr1指向t1

如果想将一个指针变量固定地与一个对象相联系(即该指针变量始终指向一个对象),可以将它指定为const型指针变量。往往用常指针作为函数的形参。

d、指向常变量的指针变量

定义指向常变量的指针变量的一般形式为

const 类型名 *指针变量名;

const char *ptr;

指针变量ptr指向的char变量是常变量,不能通过ptr来改变其值的。如果一个变量已被声明为常变量,只能用指向常变量的指针变量指向它,而不能用一般的(指向非const型变量的)指针变量去指向它。把“变量”换成对象,上述概念也适用。注意,这里指向常变量的指针变量是可以改变指向的。

     指向常变量的指针变量除了可以指向常变量外,还可以指向未被声明为const的变量。此时不能通过此指针变量改变该变量的值。如果函数的形参是指向非const型变量的指针,实参只能用指向非const变量的指针,而不能用指向const变量的指针。

     当希望在调用函数时对象的值不被修改,就应当把形参定义为指向常对象的指针变量,同时用对象的地址作实参(对象可以是const或非const型)。如果要求该对象不仅在调用函数过程中不被改变,而且要求它在程序执行过程中都不改变,则应把它定义为const型。

3)对象的常引用

    如果不希望在函数中修改实参t1的值,可以把引用变量t声明为const(常引用),函数原型为

 void fun(const Time &t);

    则在函数中不能改变t的值,也就是不能改变其对应的实参t1的值。