非静态成员函数更新静态数据。

3

显然,非静态成员函数可以读取静态数据。实际上,这是拥有静态数据的重要原因之一——使实例成员函数可以读取它。

但是,从面向对象设计的角度来看,是否存在将非静态成员函数更新静态数据变量的好理由?

我知道一个简单的例子,我们可能想要保持特定对象已创建实例的计数器。所以我们可以让构造函数更新一个静态的int计数器。像这样:

class Foo
{
    static int ctr;

    Foo()
    {
        ctr++;
    }
}

除了这个特定的例子,还有没有其他好的一般理由来更新静态变量的非静态函数?

个人认为这似乎有点傻,但我无法确定究竟是什么困扰着我。


为什么不允许更新静态变量?如果你真的不想更新它,为什么不将其声明为“const”? - Colonel Thirty Two
什么情况下使用静态变量,并且不更新它?一般来说,静态变量应该相当少见,但如果需要,就必须使用它。 - Ben Voigt
静态变量中的“static”代表内存空间上的“静态位置(地址)”,因此在内存中只存在一个实体,该实体在该类的所有实例之间共享。在共享的本质上,必须有能力修改静态变量。你能想象除了实例成员之外,还有什么最适合修改静态变量吗? - Fumu 7
2个回答

3
有点像。您可能有工人负责在重复的情况下丢弃任务,并且您可以通过拥有一组静态的正在处理的任务来检查它们是否重复来实现此目的。
这种静态使用的问题在于,这意味着每个程序只能有一个这样的类。如果较大的程序的所有者想要运行此类两次怎么办?糟糕。或者,如果程序的另一个部分决定真的需要此任务管理系统用于其他事情怎么办?糟糕。任何小程序都可以成为大程序的一部分,以节省线程和其他资源(我特别习惯于Java上下文,其中JVM本身非常昂贵)。
因此,当您感觉需要此模式时,请尝试拥有一个伞类来拥有候选静态数据作为非静态数据,并为许多子实例拥有一个伞类实例。例如:
class Worker {
    static set<WorkItem*> inProcess; // the old way of doing it
    void work(WorkItem* w) {
        inProcess.add(w);
}

应该变成

class Worker {
    Manager* manager; // shared between all instances, until your program grows
    void work(WorkItem* w) {
        manager->accept(w);
    }
}

class Manager {
    set<WorkItem> inProcess;
    void accept(WorkItem* w) {
        inProcess.add(w);
    }
}

这个问题适用于任何静态的、非常量数据。但是,随着数据从只读到读写,问题变得越来越危险。单例模式是一种反模式

经理是否也可以注册一个“工人”(以便每个“工人”都由一个“经理”注册)?在这种情况下,我们想知道经理如何/何时注册工人。您将如何避免部分构建的“工人”的this泄漏?您会保护构造函数并为“工人”使用工厂函数吗? - Tobias
@Tobias 这是一个不同的设计问题,但如果manager应该拥有worker,我会让manager负责创建它。manager.createWorker(...)将创建一个新的worker,然后在创建完成后保存它。 - djechlin

0

来自书籍

《C++编程思想》第二版,Bruce Eckel,MindView公司总裁。

C++中的静态成员

有时您需要一个单一的存储空间供类的所有对象使用。在C语言中,您会使用全局变量,但这不是很安全。全局数据可以被任何人修改,并且它的名称可能与大型项目中的其他相同名称冲突。如果数据可以存储为全局数据,但在类内部隐藏,并与该类明确关联,那将是理想的。这可以通过类内的静态数据成员实现。对于静态数据成员,有一个单独的存储空间,无论您创建多少个该类的对象。所有对象共享该数据成员的相同静态存储空间,因此它是它们之间“通信”的一种方式。但是静态数据属于类;其名称在类内部作用域内,可以是公共的、私有的或受保护的。


这是一个很好的解释,但我认为需要注意的是类内部的静态数据仍然是单例反模式,即太过全局化。 - djechlin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接