8.8 特殊函数成员
除了构造函数、复制构造函数和析构函数外,其他成员函数被用来提供特定的功能,一般来说,提供给外部访问的函数称为接口,访问权限为public,而一些不供外部访问,仅仅作为内部功能实现的函数,访问权限设为private。本节主要讨论函数成员的一些特殊用法。
8.8.1 静态成员函数
成员函数也可以定义成静态的,与静态数据一样,系统对每个类只建立一个函数实体,该实体为该类的所有对象共享。静态成员函数用法示例见代码8.18。
代码8.18 静态成员函数的用法StaticFuncMember
<——————————————文件名:computer.h——————————————-> 01 #include<iostream> 02 using namespace std; 03 class computer 04 { 05 private: 06 char*name; 07 float price; 08 static float total_price;//静态数据成员 09 public: 10 computer(const char*chr,const float p)//构造函数,模拟买电脑操作 11 { 12 name=new char[strlen(chr)+1]; 13 strcpy(name,chr); 14 price=p; 15 total_price+=p; 16 } 17 ~computer()//析构函数,模拟退掉电脑的操作 18 { 19 delete[]name; 20 total_price-=price; 21 } 22 static void print_total()//static函数原则上只能访问静态数据成员 23 24 { 25 cout<<"总价:"<<total_price<<endl; 26 } 27 static void print(computer&com);//静态成员函数print()原型,如果要访问 28 //某具体对象,必须传递参数 29 }; 30 void computer:print(computer&com)//静态成员函数print()实现 31 { 32 cout<<"名称"<<com.name<<endl; 33 cout<<"价格"<<com.price<<endl; 34 } <———————————-文件名:example818.cpp———————————————-> 35 #include"computer.h" 36 float computer:total_price=0;//初始化 37 int main() 38 { 39 computer comp1("IBM",7000);//声明类对象comp1,初始化,买入 40 //类名加作用域限定符访问static成员函数,传参comp1 41 computer:print(comp1); 42 computer:print_total();//类名加作用域限定符访问static成员函数 43 computer comp2("ASUS",4999);//声明类对象comp2,初始化,买入 44 computer:print(comp2);//传递参数comp2 45 computer:print_total(); 46 comp2.~computer();//析构函数调用,退还电脑 47 computer:print_total(); 48 return 0; 49 }
输出结果如下所示。
名称IBM 价格7000 总价:7000 名称ASUS 价格4999 总价:11999 总价:7000
注意
使用VC 6编译上述代码时,必须选择Release模式,选择Debug模式时,程序运行会报错,这可能是VC 6编译器设计上的小Bug,关于两种编译模式的介绍请参考第20章。
【代码解析】从代码8.18可以看出,因为静态成员函数是被该类所有对象共享的,因此,如果需要在静态函数成员内访问类的非静态成员,需要将对象的引用或指向对象的指针作为参数,所以在代码第27行的类定义中采取了“static void print(computer&com);”的形式,在静态函数内访问静态数据成员显得比较自然。
结合代码8.18,强调一下静态成员函数的用法。
(1)静态成员函数既可以定义为inline的,如“static void print_total()”,又可定义在函数外部,如“void computer:print(computer&com)”,在类定义之外时,不使用static。
(2)静态成员函数不与特定的对象联系,基本的调用格式如下所示。
类名:静态成员函数名(参数表);
如代码8.18中的“computer:print_total();”和“computer:print(comp1);”,当然,将其当做是某个对象的成员也没有错,比如,只要comp1和comp2有效,将“computer:print_total();”写成“comp1.print_total();”和“comp2.print_total();”都是合法的,但不如使用类名来调用,意义更加直观。