类和对象(二)
整理自《面向对象程序设计》
1.静态成员
我们知道全局变量能够实现数据共享,但是由于全局变量在程序的任何地方都可以被改变,很可能因为以此失误,全局变量的值就被修改,导致程序失败。因此为了安全起见,在程序中很少用全局变量。
如果想在同类中的多个对象之间实现数据共享,又不用全局变量,那么可以用静态成员。静态成员包含静态数据成员和静态成员函数。
1.1静态数据成员
在类中定义静态成员的方法就是在该成员前加static关键字。
【在类中定义一个静态数据成员 count,用来统计创建的Time类对象的个数】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Time.h class Time { private: int hour; int minute; int sec; public: static int count; //count 为静态数据成员 Time(int h, int m, int s); ~Time(); void show(); }; //Time.cpp #include<iostream> using namespace std; #include"Time.h" Time::Time(int h, int m, int s) { cout << "create one object\n"; hour = h; minute = m; sec = s; count++;//每创建一个对象,count就加1 } Time::~Time() { cout << "destruct one object\n" ; count--; cout << "The number of object is "<<count<<endl; } void Time::show() { cout << "The number of object is " << count << endl; cout << hour << ":" << minute << ":" << sec << endl; } //main.cpp #include"Time.h" #include<cstdio> #include<cstdlib> int Time::count = 0; void test() { Time time1(10, 15, 20); time1.show(); Time time2(11, 20, 30); time2.show(); } int main() { test(); system("pause"); } /* create one object The number of object is 1 10:15:20 create one object The number of object is 2 11:20:30 destruct one object The number of object is 1 destruct one object The number of object is 0 */
关于静态数据成员的几点说明:
- 静态数据成员不属于任何一个对象,而是属于类。静态数据成员的值对所有对象都是一样的,在内存中只占一份空间,为所有对象所共享,即使不定义对象,编译时也为静态数据成员分配空间。
- 静态数据成员必须进行初始化。由于类的声明是抽象的,静态数据成员的初始化需要在程序的全局区域中进行,并指明其数据类型与所属类的类名,格式为:数据类型 类名::变量名=值;例如:int Time::count=0;
- 在类的外部,对于在类的public部分说明的静态数据成员,可以不使用成员函数而直接访问,但使用时必须用类名指明其所属的类。格式为: 类名::静态数据成员名 例如可以在main函数中使用 cout<<Time::count;语句来访问静态数据成员count。但是,在protected和private部分说明的静态数据成员,在类的外部不能直接访问,只能通过类的成员函数访问。
1.2静态成员函数
所谓的静态成员函数就是使用static关键字声明的成员函数。
【在类中增加一个静态成员函数,用来输出静态数据成员count的值】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Time.h class Time { private: static int count; //count 为私有静态数据成员 int hour; int minute; int sec; public: Time(int h, int m, int s); static int get(); void show(); }; //Time.cpp #include<iostream> using namespace std; #include"Time.h" Time::Time(int h, int m, int s) { hour = h; minute = m; sec = s; count++;//每创建一个对象,count就加1 } int Time::get() { return count; } void Time::show() { cout << hour << ":" << minute << ":" << sec << endl; } //main.cpp #include"Time.h" #include<cstdio> #include<cstdlib> #include<iostream> int Time::count = 0; using namespace std; int main() { cout << Time::get() << endl;//调用公有静态成员函数 Time t1(0, 0, 0); Time t2(1, 1, 1); Time t3(2, 2, 2); cout << Time::get() << endl; cout << t1.get() << endl; t1.show(); t2.show(); t3.show(); system("pause"); } /* 0 3 3 0:0:0 1:1:1 2:2:2 */
关于静态成员函数的几点说明:
- 在类体外定义静态成员函数时,static属性不用再写。
- 类的普通成员函数可以访问类中的普通数据成员和静态数据成员,访问方式完全相同。
- 类的静态成员函数只能用来访问同一个类中的静态数据成员,达到对同一个类中对象之间共享的数据进行维护的目的,不能访问类中的普通数据成员。
- 在类外可以通过对象或类调用类中的公有静态成员函数,如main函数中的语句Time::get();和t1.get();
2.对象指针
2.1指向类对象的指针
类也是一种数据类型,可以定义一个指向类的指针变量,用来存放某个对象的地址,使其指向该对象。对象指针遵循一般变量指针的各种规则。
//例如已定义了类Time,则可定义指向该类的指针如下: Time time1; Time *p;//定义p为指向Time类对象的指针变量 p=&time1;//指针变量p指向对象time1 p->set(10,10,10);//通过指向对象的指针变量p来调用类的共有成员函数 (*p).show();
2.2指向对象成员的指针
2.2.1指向对象数据成员的指针
定义指向对象数据成员的指针的方法与定义指向普通变量的指针方法相同。
假设Time类的数据成员hour为公有的整型数据,可以在类外通过指向对象数据成员的指针来访问hour.
Time t; int *p; t.hour=10; p=&t.hour; cout<<*p<<endl;
在类的外部不能直接访问类的私有成员,通过指向对象数据成员的指针来访问的数据成员必须具有public权限。
2.2.2指向对象成员函数的指针
指向对象成员函数的指针变量用来存放该函数代码段的起始地址,该地址不是类的成员,只是一个指针变量而已。
定义指向成员函数的指针变量格式如下:
数据类型名(类名::*指针变量名)(形参列表);
使指针指向一个公有成员函数的格式如下:
指针变量名=&类::成员函数名;
调用指针指向的对象的成员函数的语句格式如下:
(对象.*指针变量名)(实参列表);
【有关指向对象成员函数的指针的使用方法】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Time.h class Time { private: static int count; //count 为私有静态数据成员 int hour; int minute; int sec; public: void set(int ,int ,int); void show(); }; //Time.cpp #include<iostream> using namespace std; #include"Time.h" void Time::set(int h, int m, int s) { hour = h; minute = m; sec = s; } void Time::show() { cout << hour << ":" << minute << ":" << sec << endl; } //main.cpp #include"Time.h" #include<cstdio> #include<cstdlib> #include<iostream> int Time::count = 0; using namespace std; int main() { Time time; void(Time::*p)(int, int, int); p = &Time::set; (time.*p)(10, 1, 1); time.show(); system("pause"); } /* 10:1:1 */
该程序通过指向成员函数set()的指针变量p调用成员函数完成相应功能,(time.*p)(10,1,1)等价于time.set(10,1,1);。
3.友元
在一个类中,类的私有成员是绝对不允许类外的任何函数和外部类进行存取的。这种限制给两个或多个类共享同一函数带来了较大的开销。为此C++提供了一种辅助手段,允许其他类或函数去访问一个类的私有数据,那就是友元。利用关键字friend将其他类的成员函数或其他类声明为友元,这样类中的私有和保护成员就可以被友元访问了。
3.1友元函数
在本类以外的其他地方定义一个函数(可以是一个普通函数,也可以是其他类的成员函数),将这个函数说明为某个类的友元函数的方法是在该类的定义中提供一个以关键字friend开头的函数原型,格式为:
friend 函数返回值的类型 函数名(形参表);
- 必须在类的定义中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型。友元函数的说明可以出线在类的任何地方,包括在private和public部分。
- 在类外定义友元函数时,与普通函数一样,不用在函数名前用类名加以限制。也不用在函数名前加关键字friend。
- 友元函数一定要带参数,而且参数一般是对象的引用,调用友元函数时,在实参中需要指出要访问的对象。
- 友元函数的调用与一般函数的调用方式和原理一致。
- C++ 不允许将某个函数的构造函数、析构函数和虚函数声明为友元函数。
【友元函数的使用】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Time.h class Time { private: int hour; int minute; int sec; public: Time (int ,int ,int); void show1(); friend void show(Time &t);//声明友元函数 }; //Time.cpp #include<iostream> using namespace std; #include"Time.h" Time::Time(int h, int m, int s) { hour = h; minute = m; sec = s; } void Time::show1() { cout << "用成员函数显示时间:"<<hour << "点" << minute << "分" << sec << "秒"<<endl; } //main.cpp #include"Time.h" #include<cstdio> #include<cstdlib> #include<iostream> using namespace std; void show(Time &t) { cout << "用友元函数显示时间:" << t.hour << ":" << t.minute << ":" << t.sec << endl; } int main() { Time t(10, 10, 10); show(t); t.show1(); system("pause"); } /* 用友元函数显示时间:10:10:10 用成员函数显示时间:10点10分10秒 */
例中的友元函数是一个普通函数,这个函数也可以是另外一个类的成员函数。
3.2友元类
同函数一样,在类的声明中可以声明另一个类为本类的友元,这时称为友元类。如果将类X声明为类Y的友元(类),那么,类X的所有成员函数都称为类Y的友元函数。
格式:friend class 类名 X;
- 类名必须是程序中的一个已定义过的类。
- 友元类的所有成员函数都可视为该类的友元函数,而且可以存取该类的私有成员和保护成员。
- 友元关系不能被继承和传递。
- 友元关系是单向的,不具有交换性(由X是Y的友元,不能推出Y是X的友元)。
【友元类的应用】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Time.h class Time { private: friend class A; int hour; int minute; int sec; public: Time (int ,int ,int); }; //Time.cpp #include<iostream> using namespace std; #include"Time.h" Time::Time(int h, int m, int s) { hour = h; minute = m; sec = s; } //main.cpp #include"Time.h" #include<cstdio> #include<cstdlib> #include<iostream> using namespace std; class A { public: void show(Time t); }; void A::show(Time t) { cout << t.hour << ":" << t.minute << ":" << t.sec << endl; } int main() { Time time(10, 10, 10);//生成对象time A obj;//生成对象obj obj.show(time);//调用obj.show访问time的成员 system("pause"); } /* 10:10:10 */
在函数show()中可以访问类Time的私有数据成员hour,minute和sec,但必须利用向其参数t传递对象名的方式进行。