【静态数据成员】:
①声明:
在类的数据成员前面加上关键字static将类数据成员声明为静态数据成员。例静态数据成员i的声明
static int i ;
②定义:
静态数据成员在程序开始运行时必须存在(定义空间)。对于单文件程序,类的定义与全局变量相同,一般在主函数之前定义。对于多文件程序,静态数据成员的定义要放在类的外部实现中,即与在类成员的成员函数实现的文件中定义,不能在类定义内部定义,也不能在包含类定义的头文件的类外部定义。
若若i为Student类的静态数据成员,则i定义的语句为:
int Student::i = 0;
注意整条语句中是没有static关键字的。
静态数据成员的声明和定义一定是分开进行的。声明出必须现在类内部,定义则必须在类外部。声明有关键字static,定义时无关键子static但要指定类名。
注意:
①在所有类的对象空间中,没有静态数据成员的空间,即静态数据成员属于抽象的类所有,而不是某个具体的对象所有。所以静态数据成员可以使用类名引用即Student::i
。
②静态数据成员的空间分配不能在构造函数里执行,也不会被析构函数所析构。
③静态数据成员可以被该类的所有对象的成员函数所使用。静态数据成员在第一个对象被创建之前就存在。
【静态成员函数】:
①静态成员函数在声明时只是比成员函数之前多一个关键字static,定义的位置和成员函数一样。
②静态成员函数与静态数据成员一样为类所有,不属于某个对象。
③静态成员函数不能默认访问任何一个类的非静态数据成员,因为非静态数据成员属于对象所有
④静态成员函数可以与静态数据成员一样可以有两种访问方式,通过类名引用,和通过对象名引用,但要注意通过对象名引用也只是引用对象名的类型。
⑤静态成员函数与非静态成员函数的本质区别是,静态成员函数没有隐含指向自身对象的this指针,而非静态成员函数有一个指向当前对象的this指针。即所有非静态成员函数都隐式包含这一个形参:Student* this,其接受的实参就是对象名。例s1和s2为Student的对象,fn()为Student类的非静态成员函数,则对于fn()的访问为:
s1.fn()的编译解释是:s1对象名作为指向s对象的句柄,传递给隐式形参this,所以对fn()函数体的所有操作都属于s1对象所有,与s2毫无关系。
这也是为什么静态成员函数不能访问任何非静态数据成员的本质原因!
【类的友元】:
友元的声明:
类的友元在类的内部有声明,必须在类的定义之后有定义,否则对友元来说,会出现类找不到该类的错误
①普通函数可以是类的友元
②一个类的成员函数可以是另一个类的友元
③一类可以是另一个类的友元,此时成为友类。
友元可以跟类的成员函数一样无限制的访问类的任何成员,但与成员函数不同,友元不属于类,所以不能通过对象名去调用它。
友元的使用:
①友元函数的调用只和该函数本身的性质有关。
②友元的形参可以是任何与该类无关的形参,形参数量不限。但是需要注意:
如果该友元函数需要访问该类的非静态成员,则友元函数的形参必须有该类的对象的引用形参,即友元函数必须接收某一对象的引用作为其中一个实参。因为类的非静态数据成员是属于类的实例即对象所有,所以当友元函数要访问该数据成员时,就要有足够的信息来指明要访问的是哪一个对象的数据成员,所以,当友元函数要访问类的非静态数据成员时,就要有一个特定的形参"对象类型的引用",但还可以有其他与类无关的形参
如果该友元不访问任何该类的非静态成员,则可以形参随意,但是这样友元基本无价值。
③【友元函数】:
一个函数(此函数可以是普通函数或另外一个类的成员函数)被声明为是某一个类的友元函数时,该函数可以访问此类的所有成员,但该函数的定义与该类的定义在程序上的代码位置是有规定的,即一个类若声明了某个函数是其友元函数,则该类定义的位置必须在该友元函数定义的位置之前,否则对该友元函数来说该类类型是不存在的,即找不到该类,程序就会出错。友元函数必须在该类的定义之后声明和定义,如果该函数声明和定义是分开的,则该函数声明部分也必须在该类的定义的位置之后声明。
④【友元类】:
①class1类是class2类的友元类:class1类的所有成员函数都可以访问class2类的数据成员,同样的,如果class1的成员函数需要访问class2的非静态成员,则该成员函数必须有一个参数是class2类类型的引用形参。
一般情况:class1类的定义位置必须在class2类定义的位置之后,这样class2类对class1类来说已存在,class1类的成员函数才可以正常访问class2类的成员。否则必须按下面的特殊情况处理。
特殊情况:如果class1类的定义位置在class类定义位置之前,则①首先:class1类中所有需要访问class2类数据成员的成员函数必须放在class2类定义的后面实现,即这些成员函数不但必须在class1类外部怎么实现,而且还必须在class2类定义位置之后实现。②最后:还必须在所有想要要 访问class2类的数据成员 的 class1类的成员函数 之前的位置将class2声明为class1的友元类,即此时class1类与class2类互为友元类。但事实上class2类声明为class1类的友元类只是为了告诉class1类之后的成员函数,class2类已存在,而额外造成的结果两个类互为友元类。这也是两个类互为友元类类与类之间的必须要遵守的原则。
【注意】在class1类中,只有满足上述①和②条件的成员函数才可以访问class2类的数据成员。我们知道当满足①和②时class2也成为了class1的友元类,所以class2也有可能访问class1的所有成员,由于class1类定义的位置在class2类定义的位置之前,所以对class2类来说class1类类型已存在,所以class2的所有成员函数都可以直接访class1类对象的成员。
所以,两个类互为友元类时,定义位置在前的类需要满足上述①和②条件
总结:如果class1类是class2类的友元类,且class2类不希望是class1类的友元类,则必须把class1类的定义放在class2类的定义之后。