首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

C++ static 种成员

2012-10-30 
C++static 类成员节选自《C++ Primer》,还是书上写的最清楚。??12.6.?static?类成员?对于特定类类型的全体对

C++ static 类成员


节选自《C++ Primer》,还是书上写的最清楚。

?

?

12.6.?static?类成员

?

对于特定类类型的全体对象而言,访问一个全局对象有时是必要的。也许,在程序的任意点需要统计已创建的特定类类型对象的数量;或者,全局对象可能是指向类的错误处理例程的一个指针;或者,它是指向类类型对象的内在自由存储区的一个指针。

?

然而,全局对象会破坏封装:对象需要支持特定类抽象的实现。如果对象是全局的,一般的用户代码就可以修改这个值。类可以定义?静态成员,而不是定义一个可普遍访问的全局对象。

?

通常,非?static?数据成员存在于类类型的每个对象中。不像普通的数据成员,static?数据成员独立于该类的任意对象而存在;每个?static?数据成员是与类关联的对象,并不与该类的对象相关联。

?

正如类可以定义共享的?static?数据成员一样,类也可以定义?static?成员函数。static?成员函数没有?this?形参,它可以直接访问所属类的?static?成员,但不能直接使用非?static?成员。

使用类的?static?成员的优点

使用?static?成员而不是全局对象有三个优点。

    ?成员的名字是在类的作用域中,因此可以避免与其他类的成员或全局对象名字冲突。

    可以实施封装。static?成员可以是私有成员,而全局对象不可以。

    通过阅读程序容易看出?static?成员是与特定类关联的。这种可见性可清晰地显示程序员的意图。

定义?static?成员

在成员声明前加上关键字?static?将成员设为?staticstatic?成员遵循正常的公有/私有访问规则。

?

例如,考虑一个简单的表示银行账户的类。每个账户具有余额和拥有者,并且按月获得利息,但应用于每个账户的利率总是相同的。可以按下面的这样编写这个类

     class Account {     public:         // interface functions here         void applyint() { amount += amount * interestRate; }         static double rate() { return interestRate; }         static void rate(double); // sets a new rate     private:         std::string owner;         double amount;         static double interestRate;         static double initRate();     };

这个类的每个对象具有两个数据成员:owner?和?amount。对象没有与?static?数据成员对应的数据成员,但是,存在一个单独的interestRate?对象,由?Account?类型的全体对象共享。

使用类的?static?成员

可以通过作用域操作符从类直接调用?static?成员,或者通过对象、引用或指向该类类型对象的指针间接调用。

     Account ac1;     Account *ac2 = &ac1;     // equivalent ways to call the static member rate function     double rate;     rate = ac1.rate();        // through an Account object or reference     rate = ac2->rate();       // through a pointer to an Account object     rate = Account::rate();   // directly from the class using the scope operator

像使用其他成员一样,类成员函数可以不用作用域操作符来引用类的?static?成员:

     class Account {     public:          // interface functions here          void applyint() { amount += amount * interestRate; }     };

12.6.1.?static?成员函数

?

Account?类有两个名为?rate?的?static?成员函数,其中一个定义在类的内部。当我们在类的外部定义?static?成员时,无须重复指定?static?保留字,该保留字只出现在类定义体内部的声明处:

     void Account::rate(double newRate)     {         interestRate = newRate;     }

static?函数没有?this?指针

static?成员是类的组成部分但不是任何对象的组成部分,因此,static?成员函数没有?this?指针。通过使用非?static?成员显式或隐式地引用?this?是一个编译时错误。

?

因为?static?成员不是任何对象的组成部分,所以?static?成员函数不能被声明为?const。毕竟,将成员函数声明为?const?就是承诺不会修改该函数所属的对象。最后,static?成员函数也不能被声明为虚函数。我们将在第 15.2.4 节学习虚函数。

12.6.2.?static?数据成员

static?数据成员可以声明为任意类型,可以是常量、引用、数组、类类型,等等。


static?数据成员必须在类定义体的外部定义(正好一次)。不像普通数据成员,static?成员不是通过类构造函数进行初始化,而是应该在定义时进行初始化。

?

保证对象正好定义一次的最好办法,就是将?static?数据成员的定义放在包含类非内联成员函数定义的文件中。


定义?static?数据成员的方式与定义其他类成员和变量的方式相同:先指定类型名,接着是成员的完全限定名。

?

可以定义如下?interestRate

     // define and initialize static class member     double Account::interestRate = initRate();

这个语句定义名为?interestRate?的?static?对象,它是类?Account?的成员,为?double?型。像其他成员定义一样,一旦成员名出现,static?成员的就是在类作用域中。因此,我们可以没有限定地直接使用名为?initRate?的?static?成员函数,作为interestRate?初始化式。注意,尽管?initRate?是私有的,我们仍然可以使用该函数来初始化?interestRate。像任意的其他成员定义一样,interestRate?的定义是在类的作用域中,因此可以访问该类的私有成员。


像使用任意的类成员一样,在类定义体外部引用类的?static?成员时,必须指定成员是在哪个类中定义的。然而,static?关键字只能用于类定义体内部的声明中,定义不能标示为?static


特殊的整型?const static?成员

?

一般而言,类的?static?成员,像普通数据成员一样,不能在类的定义体中初始化。相反,static?数据成员通常在定义时才初始化。

?

这个规则的一个例外是,只要初始化式是一个常量表达式,整型?const static?数据成员就可以在类的定义体中进行初始化:

     class Account {     public:         static double rate() { return interestRate; }         static void rate(double);  // sets a new rate     private:         static const int period = 30; // interest posted every 30 days         double daily_tbl[period]; // ok: period is constant expression     };

?

用常量值初始化的整型?const static?数据成员是一个常量表达式。同样地,它可以用在任何需要常量表达式的地方,例如指定数组成员?daily_tbl?的维。


const static?数据成员在类的定义体中初始化时,该数据成员仍必须在类的定义体之外进行定义。


在类内部提供初始化式时,成员的定义不必再指定初始值:

     // definition of static member with no initializer;     // the initial value is specified inside the class definition     const int Account::period;

static?成员不是类对象的组成部分

普通成员都是给定类的每个对象的组成部分。static?成员独立于任何对象而存在,不是类类型对象的组成部分。因为?static数据成员不是任何对象的组成部分,所以它们的使用方式对于非?static?数据成员而言是不合法的。

?

例如,static?数据成员的类型可以是该成员所属的类类型。非?static?成员被限定声明为其自身类对象的指针或引用:

     class Bar {     public:         // ...     private:         static Bar mem1; // ok         Bar *mem2;       // ok         Bar mem3;        // error     };

类似地,static?数据成员可用作默认实参:

     class Screen {     public:         // bkground refers to the static member         // declared later in the class definition         Screen& clear(char = bkground);     private:         static const char bkground = '#';     };

非?static?数据成员不能用作默认实参,因为它的值不能独立于所属的对象而使用。使用非?static?数据成员作默认实参,将无法提供对象以获取该成员的值,因而是错误的。

?


ps:???以下关于静态成员变量

1.初始化static成员变量不能安排在类的构造函数中,因为构造函数可能一再被调用,而变量的初值却只应该设定一次。也不要把初始化安排在头文件中,因为它可能会被包含在许多地方。而应该放在main函数之中,或全域函数中,或者任何函数之外。

2.静态成员变量(函数)在类外定义时,注意不要写static,初始化时候 [类型名] [类名]::[变量名] 例如:int Base::a。

3.当静态成员变量被声明为private类型时,不能用类名::变量名 为静态成员变量赋值。

当声明为public 则可以。

4.当用类名调用静态成员函数时,调用符号是::,而不是java里的.号,也不是指针的->号

热点排行