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

时间:2011-03-14 16:49:29

标签: c++ constructor language-design language-features static-constructor

在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#)具有静态构造函数!

5 个答案:

答案 0 :(得分:20)

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

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

//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;
  }
}

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

答案 1 :(得分:13)

这对c ++来说没有意义 - 类不是第一类对象(比如java)。

(静态|任何)构造函数意味着构造了某些东西 - 并且没有构造c ++类,它们就是这样。

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

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

IMO不再需要一种语法方法来实现这一目标。

答案 2 :(得分: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的代码出现在类sample的定义中,那么您甚至可以将其作为嵌套类放在那里。你只需要在定义静态的同一个地方定义它的实例(之后通过它们的默认构造函数初始化它们,否则当然你不能push_back任何东西)。

C#是在C ++之后15 - 20年发明的,并且具有完全不同的构建模型。它提供不同的功能并不令人惊讶,并且C ++中的某些东西不像C#中那么简单。

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

答案 3 :(得分:4)

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

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成员保证在您首次尝试访问它之前进行初始化。 (可能在主要之前,但不一定)

答案 4 :(得分:2)

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

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

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