C++第六弹---静态成员与友元

静态成员

静态成员的定义或声明要加个关键static。静态成员可以通过双冒号来使用即<类名>::<静态成员名>。

我们可以使用 static 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。

静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化,如下面的实例所示。
实例:

#include 
 
using namespace std;
 
class Box
{
   public:
      static int objectCount;
      // 构造函数定义
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // 每次创建对象时增加 1
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
   private:
      double length;     // 长度
      double breadth;    // 宽度
      double height;     // 高度
};
 
// 初始化类 Box 的静态成员
int Box::objectCount = 0;
 
int main(void)
{
   Box Box1(3.3, 1.2, 1.5);    // 声明 box1
   Box Box2(8.5, 6.0, 2.0);    // 声明 box2
 
   // 输出对象的总数
   cout << "Total objects: " << Box::objectCount << endl;
 
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Constructor called.
Constructor called.
Total objects: 2

  1. 静态数据成员
  • 静态数据成员定义
    静态数据成员实际上是类域中的全局变量。所以,静态数据成员的定义(初始化)不应该被放在头文件中。 其定义方式与全局变量相同。举例如下:
    test.h文件 :
class   base
{   
       private:   
       static   const   int   _i;
      //声明,标准c++支持有序类型在类体中初始化,但vc6不支持。   
};  

test.cpp文件:

const   int   base::_i=10;//定义(初始化)时不受private和protected访问限制. 

注:不要试图在头文件中定义(初始化)静态数据成员。在大多数的情况下,这样做会引起重复定义这样的错误。即使加上#ifndef #define #endif或者#pragma once也不行。

  • 静态数据成员被 类 的所有对象所共享,包括该类派生类的对象。即派生类对象与基类对象共享基类的静态数据成员。举例如下:
class   base{   
              public   :   
              static   int   _num;//声明   
};   
        int   base::_num=0;//静态数据成员的真正定义   
        class   derived:public   base{   
};   
int main()   
{   
     base   a;   
     derived   b;   
     a._num++;   
     cout<<"base   class   static   data  number   _num   is"<
  • 静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以。举例如下:
class   base{   
          public   :   
          static   int   _staticVar;   
          int   _var;   
          void   foo1(int   i=_staticVar);//正确,_staticVar为静态数据成员   
          void   foo2(int   i=_var);//错误,_var为普通数据成员   
      }; 
  • 静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为所属类类型的指针或引用。举例如下:
class   base{   
          public   :   
          static   base   _object1;//正确,静态数据成员   
          base   _object2;//错误   
          base   *pObject;//正确,指针   
          base   &mObject;//正确,引用   
      };
  • 静态数据成员的值在const成员函数中可以被合法的改变。举例如下:
class   base{   
          public:   
          base(){_i=0;_val=0;}   
    
          mutable   int   _i;   
          static   int   _staticVal;     
          int   _val;   
          void   test()   const{//const   成员函数   
    
                _i++;//正确,mutable数据成员   
                _staticVal++;//正确,static数据成员   
                _val++;//错误   
    
          }   
      };   
      int   base::_staticVal=0;  
  • 公共静态数据成员可被类的外部访问,保护或私有静态数据成员只可被类的内部访问。

静态数据成员经常被用于以下几种场合:
(1)用来保存流动变化对象的个数;
(2)作为一个标志,指示一个特定的动作是否发生;
(3)一个指向链表第一成员或最后一个成员的指针。

  1. 静态成员函数
  • 静态成员函数的地址可用普通函数指针储存,而普通成员函数地址需要用类成员函数指针来储存。举例如下:
class   base{   
              static   int   func1();   
              int   func2();   
          };   
    
          int   (*pf1)()=&base::func1;//普通的函数指针   
          int   (base::*pf2)()=&base::func2;//成员函数指针  
  • 静态成员函数不可以调用类的非静态成员。因为静态成员函数不含this指针。
  • 静态成员函数不可以同时声明为 virtual、const、volatile函数。举例如下:
class   base{   
              virtual   static   void   func1();//错误   
              static   void   func2()   const;//错误   
              static   void   func3()   volatile;//错误   
        };  

最后要说的一点是,静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。

友元

采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员,这时可以将这些函数定义为该函数的友元函数。除了友元函数外,还有友元类,两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。

  1. 友元函数
    友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
    friend 类型 函数名(形式参数);

    友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。一个函数可以是多个类的友元函数,只需要在各个类中分别声明。友元函数的调用与一般函数的调用方式和原理一致。

  2. 友元类
    友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
    当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
    friend class 类名;
    其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

    例如,以下语句说明类B是类A的友元类:

       class A
       {
              …
       public:
              friend class B;
              …
       };

经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。

注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的声明

友元示例:

#include  
using namespace std; 
class Internet 
{ 
public: 
Internet(char *name,char *address) // 改为:internet(const char *name , const char *address)
{ 
strcpy(Internet::name,name); 
strcpy(Internet::address,address); 
} 
friend void ShowN(Internet &obj);   //友元函数的声明 
public:              // 改为:private
char name[20]; 
char address[20]; 
}; 
void ShowN(Internet &obj)        //函数定义,不能写成,void Internet::ShowN(Internet &obj) 
{ 
cout<

上面的代码通过友元函数的定义,我们成功的访问到了a对象的保护成员name,友元函数并不能看做是类的成员函数,它只是个被声明为类友元的普通函数,所以在类外部函数的定义部分不能够写成void Internet::ShowN(Internet &obj),这一点要注意。

你可能感兴趣的:(C++第六弹---静态成员与友元)