1、静态成员
静态数据成员是一种特殊的数据成员,它以关键字static开头。例如
class Box
{public:
int volume( );
private:
static int height; //把height定义为静态的数据成员
int width;
};
如果希望各对象中的height的值是一样的,就可以把它定义为静态数据成员,这样它就为各对象所共有,所有对象都可以引用它。静态的数据成员在内存中只占一份空间。静态数据成员不属于某一个对象,静态数据成员是在所有对象之外单独开辟空间。只要在类中定义了静态数据成员,即使不定义对象,也为静态数据成员分配空间,它可以被引用。静态数据成员是在程序编译时被分配空间的,到程序结束时才释放空间。
静态数据成员可以初始化,但只能在类体外进行初始化。如
int Box∷height=10; //表示对Box类中的数据成员初始化
其一般形式为
数据类型类名∷静态数据成员名=初值;
不必在初始化语句中加static。
不能用参数初始化表对静态数据成员初始化。如在定义Box类中这样定义构造函数是错误的:
Box(int h,int w,int len):height(h){ } //错误,height是静态数据成员
如果未对静态数据成员赋初值,则编译系统会自动赋予初值0。
静态数据成员既可以通过对象名引用,也可以通过类名来引用。
cout<<b.height<<endl; //通过对象名b引用静态数据成员
cout<<Box∷height<<endl; //通过类名引用静态数据成员
静态数据成员并不是属于对象的,而是属于类的,但类的对象可以引用它。
如果静态数据成员被定义为私有的,则不能在类外直接引用,而必须通过公用的成员函数引用。全局变量破坏了封装的原则,不符合面向对象程序的要求。
静态数据成员的作用域只限于定义该类的作用域内(如果是在一个函数中定义类,那么其中静态数据成员的作用域就是此函数内)。在此作用域内,可以通过类名和域运算符“∷”引用静态数据成员,而不论类对象是否存在。
成员函数也可以定义为静态的,在类中声明函数的前面加static就成了静态成员函数。如
static int volume( );
静态成员函数是类的一部分,而不是对象的一部分。如果要在类外调用公用的静态成员函数,要用类名和域运算符“∷”。如
Box∷volume( );
实际上也允许通过对象名调用静态成员函数,如
a.volume( );
但这并不意味着此函数是属于对象a的,而只是用a的类型而已。
与静态数据成员不同,静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员。
静态成员函数与非静态成员函数的根本区别是: 非静态成员函数有this指针,而静态成员函数没有this指针。由此决定了静态成员函数不能访问本类中的非静态成员。
静态成员函数可以直接引用本类中的静态数据成员。
如果非要在静态函数中引用本类的非静态成员,应该加对象名和成员运算符“.”。如cout<<a.width<<endl; //引用本类对象a中的非静态成员
在C++程序中最好养成这样的习惯: 只用静态成员函数引用静态数据成员,而不引用非静态数据成员。
2、友元
如果在本类以外的其他地方定义了一个函数(这个函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数),在类体中用friend对其进行声明,此函数就称为本类的友元函数。友元函数可以访问这个类中的私有成员。友元包括友元函数和友元类。
C++允许对类作“提前引用”的声明,即在正式声明一个类之前,先声明一个类名,表示此类将在稍后声明。它只包含类名,不包括类体。但是,只有在正式定义类后才能定义对象。在对一个类作了提前引用声明后,可以用该类的名字去定义指向该类型对象的指针变量或对象的引用变量。这是因为指针变量和引用变量本身的大小是固定的,与它所指向的类对象的大小无关。
不仅可以将一个函数声明为一个类的“朋友”,而且可以将一个类(例如B类)声明为另一个类(例如A类)的“朋友”。这时B类就是A类的友元类。友元类B中的所有函数都是A类的友元函数,可以访问A类中的所有成员。
在A类的定义体中用以下语句声明B类为其友元类:
friend B;
声明友元类的一般形式为
friend 类名;
(1) 友元的关系是单向的而不是双向的。
(2) 友元的关系不能传递。
在使用友元时,要注意到它的副作用,不要过多地使用友元,只有在使用它能使程序精炼,并能大大提高程序的效率时才用友元。
一个例子如下:
#include <iostream>
using namespace std;
class Data;
class Time
{
public:
Time(int,int,int);
void display(Data&);
private:
int hour;
int minute;
int sec;
};
class Data
{
public:
Data(int,int,int);
friend void Time::display(Data&);
private:
int month;
int day;
int year;
};
Time::Time(int h,int m,int s)
{
hour=h;
minute=m;
sec=s;
}
void Time::display(Data& d)
{
cout<<d.month<<"/"<<d.year<<endl;
cout<<hour<<":"<<minute<<":"<<sec<<endl;
}
Data::Data(int m,int d,int y)
{
month=m;
day=d;
year=y;
}
int main()
{
Time t1(10,13,56);
Data d1(12,25,56);
t1.display(d1);
return 1;
}