30

在 C++ 中没有静态构造函数的理由是什么?

如果允许,我们将在一个地方以一种非常有组织的方式初始化其中的所有静态成员,如下所示:

//illegal C++
class sample
{
public:

    static int some_integer;
    static std::vector<std::string> strings;

    //illegal constructor!
    static sample()
    {
       some_integer = 100;
       strings.push_back("stack");
       strings.push_back("overflow");
    }
};

在没有静态构造函数的情况下,很难有静态向量,并用值填充它,如上所示。静态构造函数优雅地解决了这个问题。我们可以以非常有组织的方式初始化静态成员。

那么为什么'C++'没有静态构造函数呢?毕竟,其他语言(例如 C#)都有静态构造函数!

4

5 回答 5

22

使用静态初始化顺序问题作为不向语言引入此功能的借口一直是现状问题 - 它没有被引入是因为它没有被引入,人们一直认为初始化顺序是不引入这个功能的原因介绍一下,即使订单问题有一个简单且非常直接的解决方案。

初始化顺序,如果人们真的想解决这个问题,他们会有一个非常简单直接的解决方案:

//called before main()

int static_main() {

ClassFoo();
ClassBar();

}

带有适当的声明:

class ClassFoo {
 static int y;
  ClassFoo() {
   y = 1;
  }
}

class ClassBar {
  static int x;
  ClassBar() {
   x = ClassFoo::y+1;
  }
}

所以答案是,没有理由不存在,至少不是技术问题。

于 2011-03-14T16:59:53.420 回答
14

这对 c++ 来说真的没有意义——类不是一流的对象(例如在 java 中)。

(static|anything) 构造函数意味着构造了某些东西 - 而 c++ 类不是构造的,它们只是构造。

您可以轻松实现相同的效果:

//.h
struct Foo {
  static std::vector<std::string> strings;
};
//.cpp
std::vector<std::string> Foo::strings(createStrings());

IMO 只是不需要另一种语法方式来做到这一点。

于 2011-03-14T16:54:37.850 回答
6

静态对象将放置在哪个翻译单元中?

一旦您考虑到必须将静态变量放置在一个(并且只有一个)TU 中的事实,那么接下来就不会“非常困难”,并在函数中为它们分配值:

// .h
class sample
{
public:
    static int some_integer;
    static std::vector<std::string> strings;
};

//.cpp

// we'd need this anyway
int sample::some_integer;
std::vector<std::string> sample::strings;

// add this for complex setup
struct sample_init {
    sample_init() {
       sample::some_integer = 100;
       sample::strings.push_back("stack");
       sample::strings.push_back("overflow");
    }
} x;

如果您真的希望代码sample_init出现在 class 的定义中sample,那么您甚至可以将其作为嵌套类放在那里。您只需在定义静态的相同位置定义它的实例(并且它们通过其默认构造函数初始化之后,否则您当然不能做push_back任何事情)。

C# 是在 C++ 之后 15-20 年发明的,并且具有完全不同的构建模型。它提供了不同的特性,而且有些东西在 C++ 中不如在 C# 中简单,这并不奇怪。

C++0x 添加了一项功能,可以更轻松地使用一些数据初始化向量,称为“初始化器列表”

于 2011-03-14T17:03:45.677 回答
5

你可以通过将你的“静态”成员放在他们自己的类中,并使用他们自己的构造函数来执行它们的初始化:

class StaticData
{
    int some_integer;
    std::vector<std::string> strings;

public:
    StaticData()
    {
       some_integer = 100;
       strings.push_back("stack");
       strings.push_back("overflow");
    }
}

class sample
{    
    static StaticData data;

public:
    sample()
    {

    }
};

您的静态data成员保证在您第一次尝试访问它之前被初始化。(可能在 main 之前,但不一定)

于 2011-03-14T17:03:32.947 回答
2

静态意味着与对象解除关联的函数。由于只构造了对象,因此静态构造函数为什么会有任何好处并不明显。

您始终可以将对象保存在已在静态块中构造的静态范围内,但您将使用的构造函数仍将被声明为非静态的。没有规则表明您不能从静态范围调用非静态方法。

最后,C++/C 将程序的开始定义main为输入函数的时间。main作为设置评估代码的“环境”的一部分,在进入函数之前调用静态块。如果您的环境要求完全控制设置和拆卸,那么很容易争辩说,它并不是真正的环境装置,而是程序的继承过程组件。我知道最后一点是一种代码哲学(并且它的基本原理可以有不同的解释),但是不应将关键代码放在“在”可执行文件将“完全控制”移交给编写的代码的正式开始之前由程序员。

于 2011-03-14T16:51:32.597 回答