C++类的静态成员(static members in classes)

来源:互联网 发布:社会调查数据 编辑:程序博客网 时间:2024/04/28 00:03

声明静态成员

  通过在成员的声明之前加上关键字static使得其与类关联在一起。与其他成员一样,静态成员可以是public或private的。静态数据成员的类型可以是常量、引用、指针、类类型
  下面以银行的账户记录为例
  

class Account{public:    void caculate()    {        amount += amount *interestRate;    }    static void rate()    {        return interestRate;    }    static void rate(double);private:    string owner;    double amount;    static double interestRate;    static double initRate;}

  类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。因此,每个Account对象将包括两个数据成员:owner和amount。只存在一个interestRate对象而且它被所有Account对象共享。
  类似的,静态成员函数也不与任何对象绑定在一起,他们不包含this指针静态成员函数不能声明称const的,也不能在static函数体内使用this指针

使用类的静态成员

  使用作用域运算符直接访问静态成员
  

    double r;    r = Account::rate();

虽然静态成员不属于类的某个对象,但是我们仍然可以使用类的对象、引用或指针来访问静态成员

    Account ac1;    Account *ac2 = &ac1;    r = ac1.rate();    r = ac2->rate();

成员函数不用通过作用域运算符就能直接使用静态成员

class Account{public:    void caculate()    {        amount += amount *interestRate;    }    static void rate()    {        return interestRate;    }    static void rate(double);private:    string owner;    double amount;    static double interestRate;    static double initRate;}

定义静态成员

  与其他的成员函数一样,我们既可以在类的内部也可以在类的外部定义静态成员函数。当在类的外部定义静态成员时,不能重复使用static关键字,该关键字只能出现在类内部的声明语句
  

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

和类的所有成员一样,当我们指向类外部的静态成员时,必须指明成员所属的类名。static关键字则指出现在类内部的声明语句中。

  因为静态数据成员不属于类的任何一个对象,所以它们并不是在创建类的对象时被定义的。这意味着它们不是由类的构造函数初始化的。而且一般来说,我们不能在类的内部初始化静态成员。相反的,必须在类的外部定义和初始化没个静态成员。和其他对象一样,一个静态数据成员只能定义一次
  类似于全局变量,静态数据成员定义在任何函数之外。因此一旦被定义,就将一直存在于程序的整个生命周期中
  我们定义静态数据成员的方式和在类的外部定义成员函数差不多。需要指定对象的类型名,然后是类名、作用于运算符以及成员自己的名字。
  

    double Account::interestRate = initRate();

这句话定义了名为interestRate的对象,该对象是类Account的静态成员,其类型是double。从类名开始,这条语句的剩余部分就都位于类的作用于之内了。因此,我们可以直接使用initRate函数。注意,虽然initRate是私有的,我们也能用它初始化interestRate。和其他成员的定义一样,interestRate的定义也可以访问类的私有成员。

要想确保对象只定义一次,最好的办法就是把静态数据成员的定义与其他非内联函数的定义放在同一个文件中。

静态成员的类内初始化

  一般来说,类的静态成员不应该在类的内部初始化。然而我么可以为静态成员提供const整数类型的类内初始值,不过要求静态成员必须是字面值常量类型的constexpr。初始值必须是常量表达式,因为这些成员本身就是常量表达式,所以它们能用在所有适合常量表达式的地方。

class Account{public:    void caculate()    {        amount += amount *interestRate;    }    static void rate()    {        return interestRate;    }    static void rate(double);private:    string owner;    double amount;    static double interestRate;    static double initRate;    static constexpr int period = 30;    double daily_tbl[period];}

如果某个静态成员的应用场景仅限于编译器可以替换它的值的情况,则一个初始化的const或constexpr static不需要分别定义。相反,如果我们将它用于不能替换的场景中,则该成员必须有一条定义语句。
  例如,如果period的唯一用途就是定义daily_tbl的维度,则不需要在Account外面专门定义peroid。此时,如果我们忽略这条定义,那么对程序非常微小的改动也可能造成编译错误,因为程序找不到该成员的定义语句。举个例子,当需要把Account::period传递给一个接受const int&的函数时,必须定义period。
  如果在类的内部提供了一个初始值,则成员的定义不能再制定一个初始值了。
  

    constexpr int Account::period;

即使一个常量静态数据成员在类内部初始化了,通常情况下也应该在类的外部定义一下该成员。

静态成员能用于某些场景,而普通成员不能

  静态成员独立于任何对象。所以,在某些非静态数据成员可能非法的场合,静态成员却可以正常使用。举个例子,静态成员可以是不完全类型特别的,静态数据成员的类型可以就是它所属的类类型。而非静态成员则受到限制,只能声明成它所属类的指针或引用
  

class Bar{public:    //..private:    static bar mem1; //正确,静态成员可以是不完全类型    Bar *mem2;      //正确,指针成员可以是不完全类型    Bar mem3;       //错误,数据成员必须是完全类型};

静态成员和普通成员的另一个区别是我们可以使用静态成员作为默认实参

class Screen{public:    //bkground表示一个在类中稍后定义的静态成员    Screen& clear(char = bkground);private:    static const char bkground;};

非静态成员不能作为默认实参,因为它的值本身属于对象的一部分。这么做的结果是无法真正提供一个对象以便总中获取成员的值,最终引发错误。

0 0
原创粉丝点击