static在 C++ 中的四种用法

static在cpp中的四种用法

  1. 静态局部变量在函数内部声明的静态变量。即使函数结束,静态局部变量的值也会保留。通常用在需要记住历史信息的情况下。
  • 注意:当我们多次调用 count() 函数时,counter 变量的值会累加,而不是每次都从 0 开始
void count() {
    static int counter = 0; // 静态局部变量
    counter++;
    cout << counter << endl;
}
// 当我们多次调用 count() 函数时,counter 变量的值会累加,而不是每次都从 0 开始。
  1. 静态全局变量在函数外部声明的静态变量。它的作用范围局限于声明它的文件内。通常用于在一个文件内共享信息,但防止其他文件访问。
  • 注意:这个 counter 变量只能在 file1.cpp 中访问,其他的 .cpp 文件是无法访问的
// file1.cpp
static int counter = 0; // 静态全局变量
// 这个 counter 变量只能在 file1.cpp 中访问,其他的 .cpp 文件是无法访问的。
  1. 静态成员变量类中的静态成员变量。它们是类的所有对象共有的静态成员变量在所有对象中有且只有一个副本。通常用在所有对象需要共享同一个变量的时候
  • 注意:所有的 MyClass 对象都会共享同一个 counter 变量
class MyClass {
public:
    static int counter; // 静态成员变量
};

// 需要在类定义的外部初始化静态成员变量
int MyClass::counter = 0;

// 所有的 MyClass 对象都会共享同一个 counter 变量。
  1. 静态成员函数:类中的静态成员函数。它们也是类的所有对象共有的。静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。通常用在需要操作静态成员变量,或者不需要访问非静态成员变量和函数的时候
  • 注意:可以通过类名和作用域解析运算符直接调用静态成员函数,不需要创建对象
class MyClass {
public:
    static int counter;
    static void increaseCounter() { // 静态成员函数
        counter++;
    }
};

int MyClass::counter = 0;
// 可以通过类名和作用域解析运算符直接调用静态成员函数,不需要创建对象。
MyClass::increaseCounter();

当我们需要在类级别而非对象级别共享数据或者函数时,就必须使用 static

额外情况:回调函数

另外,如果在类的成员函数中需要一个回调函数,而这个回调函数需要被全局访问,那么这个成员函数必须是 static 的

  • 因为非静态成员函数在调用时需要一个对象的上下文,而全局的函数无法提供这样的上下文。

在C++中,非静态成员函数需要一个对象的上下文(即this指针)来调用,但在某些全局或静态上下文(例如线程创建或排序函数)中,这个对象的上下文可能并不存在。在这种情况下,我们通常会使用静态成员函数作为回调函数

以下是一个例子,它使用C++11的std::thread类。假设我们有一个类Foo,它有一个成员函数bar,我们希望在新的线程中运行这个函数:

#include <iostream>
#include <thread>

class Foo {
public:
    void bar() {
        std::cout << "Hello, World!\n";
    }

    void startThread() {
        // error: 非静态成员函数需要一个对象的上下文
        // std::thread t(bar);
        // t.detach();
    }
};

上述代码不能正确运行,因为bar是一个非静态成员函数,而在startThread函数中,我们无法给出这样一个上下文。

如果我们将bar变为静态函数,就可以正确地创建线程:

#include <iostream>
#include <thread>

class Foo {
public:
    static void bar() {
        std::cout << "Hello, World!\n";
    }

    void startThread() {
        std::thread t(Foo::bar);
        t.detach();
    }
};

但是注意,静态成员函数无法访问类的非静态成员变量,因为这些变量是与类的实例关联的,而静态成员函数不属于任何具体的类的实例。如果需要在静态成员函数中访问非静态成员,一种常见的方法是将要访问的对象作为参数传递给静态函数。

此处bar必须static的原因

类的成员函数确实可以互相调用,不需要加 static。

然而,这里有个关键的点:在创建 std::thread 的时候,我们需要提供一个全局函数或者静态成员函数作为新线程的入口点。在这种情况下,我们不能直接传递一个非静态成员函数,因为非静态成员函数需要一个隐含的 this 指针,而我们在创建线程的时候不能提供这个 this 指针。

在上述例子中,std::thread t(bar); 这行代码会引发编译错误,因为 bar 是一个非静态成员函数,这就需要一个 Foo 类型的对象来调用它,但在创建线程的语境中我们并未提供这个对象。

如果 bar 是一个非静态成员函数,并且我们需要在一个新的线程中调用它,那么我们应该这样做:

#include <iostream>
#include <thread>

class Foo {
public:
    void bar() {
        std::cout << "Hello, World!\n";
    }

    void startThread() {
        std::thread t(&Foo::bar, this); // 在新线程中调用非静态成员函数
        t.detach();
    }
};

在这里,我们使用了 std::thread 的构造函数的另一种形式,它接受一个成员函数指针和一个类的对象,这样新的线程就可以在给定的对象上调用指定的成员函数。这个版本的 std::thread 的构造函数会保存 this 指针,并在新的线程中用它来调用成员函数 bar。

然而,如果在某些情况下我们不能(或者不想)提供一个类的对象(例如,我们正在写一个静态成员函数或全局函数,并且我们需要一个回调函数),那么我们的唯一选择就是使用静态成员函数,因为它们可以在没有对象上下文的情况下被调用

补充:线程库相关

std::thread t(Foo::bar); 这一行代码的意思是创建一个新的线程并在这个新线程上执行Foo::bar函数。

C++11引入了库来提供对线程的支持。可以使用std::thread类来创建和管理线程。它的构造函数需要一个函数或可调用对象作为参数,这个函数或可调用对象就是新线程开始执行时所调用的函数。在上面的例子中,Foo::bar就是这个函数。

然而,std::thread t(Foo::bar);这样的代码只有在Foo::bar是一个静态成员函数时才是有效的。因为非静态成员函数需要一个对象的上下文(也就是this指针),而在这个例子中,我们并没有提供这样的上下文。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值