跳转到内容

C++ 编程

来自维基教科书,开放的书籍,开放的世界

static 关键字可以在四种不同的方式中使用


Clipboard

待办事项
在结构固定后,将以上链接从子部分更改为书籍位置。


static 关键字也可以用于函数、函数内部、类、类成员(数据和函数)、结构体、联合体(但不能用于联合体的成员)中,我们将分别介绍每种用法。

永久存储
[编辑 | 编辑源代码]

使用static修饰符使变量具有静态生命周期,而对于全局变量,则使它们需要内部链接(变量将无法从同一项目中位于其他文件中的代码访问)。

静态生命周期
意味着静态变量需要在文件范围内进行初始化,并且在运行时,将一直存在并保持更改,直到程序进程关闭,静态变量的特定销毁顺序是未定义的。

static 变量实例共享相同的内存位置。这意味着它们在函数调用之间保留其值。例如,在以下代码中,函数内部的静态变量用于跟踪该函数被调用的次数

void foo() {
  static int counter = 0;
  cout << "foo has been called " << ++counter << " times\n";
}

int main() {
  for( int i = 0; i < 10; ++i ) foo();
}
内部链接

当用于自由函数、全局变量或全局常量时,它指定内部链接(与 extern 相反,后者指定外部链接)。内部链接将对数据或函数的访问限制为当前文件。

在任何函数或类之外使用的示例

static int apples = 15;
定义一个名为apples的“静态全局”变量,初始值为 15,仅从该翻译单元可见。
static int bananas;
定义一个名为bananas,初始值为 0,仅从该翻译单元可见。
int g_fruit;
定义一个名为g_fruit的全局变量,初始值为 0,从每个翻译单元可见。这种变量通常被认为是糟糕的风格。
static const int muffins_per_pan=12;
定义是一个名为muffins_per_pan的变量,仅在此翻译单元中可见。static 关键字在此处是多余的。
const int hours_per_day=24;
定义一个名为hours_per_day的变量,仅在此翻译单元中可见。(这与
static const int hours_per_day=24;
).
static void f();
声明存在一个名为f的函数,它不接受参数且没有返回值,定义在该翻译单元中。这种前向声明通常在定义相互递归函数时使用。
static void f(){;}
定义函数f()在上面声明。此函数只能从该翻译单元中的其他函数和成员调用;它对其他翻译单元不可见。
静态成员函数
[编辑 | 编辑源代码]

声明为静态的成员函数或变量在对象类型的所有实例之间共享。这意味着对于任何对象类型,成员函数或变量只有一份副本存在。

无需对象即可调用的成员函数

当用于类函数成员时,函数不将实例作为隐式 this 参数,而是表现得像自由函数。这意味着静态类函数可以在不创建类实例的情况下调用

class Foo {
public:
  Foo() {
    ++numFoos;
    cout << "We have now created " << numFoos << " instances of the Foo class\n";
  }
  static int getNumFoos() {
    return numFoos;
  }
private:
  static int numFoos;
};

int Foo::numFoos = 0;  // allocate memory for numFoos, and initialize it

int main() {
  Foo f1;
  Foo f2;
  Foo f3;
  cout << "So far, we've made " << Foo::getNumFoos() << " instances of the Foo class\n";
}
命名构造函数
[编辑 | 编辑源代码]

命名构造函数是使用静态成员函数的一个很好的例子。命名构造函数是用于创建类对象而无需(直接)使用其构造函数的函数的名称。这可能用于以下情况

  1. 绕过构造函数只能在它们的签名不同时才能重载的限制。
  2. 通过使构造函数私有来使类不可继承。
  3. 通过使构造函数私有来防止堆栈分配

声明一个使用私有构造函数创建对象并返回对象的静态成员函数。(它也可以返回指针或引用,但这种复杂性似乎没有用,并且将其变成了 工厂模式 而不是传统的命名构造函数。)

这是一个用于存储可以在任何温度标度中指定的温度的类的示例。

class Temperature
{
    public:
        static Temperature Fahrenheit (double f);
        static Temperature Celsius (double c);
        static Temperature Kelvin (double k);
    private:
        Temperature (double temp);
        double _temp;
};

Temperature::Temperature (double temp):_temp (temp) {}

Temperature Temperature::Fahrenheit (double f)
{
    return Temperature ((f + 459.67) / 1.8);
}

Temperature Temperature::Celsius (double c)
{
    return Temperature (c + 273.15);
}

Temperature Temperature::Kelvin (double k)
{
    return Temperature (k);
}

静态数据成员

[编辑 | 编辑源代码]

在数据成员中使用 static 说明符将导致该成员由所有拥有者类及其派生类的实例共享。要使用静态数据成员,您必须将数据成员声明为 static,并在类声明之外、文件范围内对其进行初始化。

当用于类数据成员时,该类的所有实例共享该变量的一个副本。

class Foo {
public:
  Foo() {
    ++iNumFoos;
    cout << "We have now created " << iNumFoos << " instances of the Foo class\n";
  }
private:
  static int iNumFoos;
};

int Foo::iNumFoos = 0;  // allocate memory for numFoos, and initialize it

int main() {
  Foo f1;
  Foo f2;
  Foo f3;
}

在上面的示例中,静态类变量 numFoos 在 Foo 类的三个实例(f1f2f3)之间共享,并记录了 Foo 类被实例化的次数。

华夏公益教科书