与静态构造函数类似,如何初始化静态数据成员?

发布于 2024-07-29 23:21:54 字数 643 浏览 10 评论 0原文

我想要一个带有私有静态数据成员的类:

class C {
    // read-only, can also be static const
    // should be filled with all characters from 'a' to 'z'
    static std::vector<char> alphabet;
public:
    C() { /* ... */ }
};

在 Java 或 C# 中,我可以创建一个“静态构造函数”,该构造函数将在创建该类的任何实例之前运行,并设置该类的静态数据成员。 它只运行一次(因为变量是只读的,并且只需要设置一次),并且由于它是类的函数,因此它可以访问其私有成员。

我可以在 C() 构造函数中添加代码来检查向量是否已初始化,如果未初始化则对其进行初始化,但这引入了许多必要的检查,并且似乎不是最佳解决方案问题。

该成员是只读的,因此它可以是static const,并且我可以在类之外定义它,但这似乎是一个丑陋的黑客行为。

如果我不想在实例构造函数中初始化它们,是否可以在类中拥有私有静态数据成员?

I want to have a class with a private static data member:

class C {
    // read-only, can also be static const
    // should be filled with all characters from 'a' to 'z'
    static std::vector<char> alphabet;
public:
    C() { /* ... */ }
};

In Java or C#, I can just make a "static constructor" that will run before I make any instances of the class, and sets up the static data members of the class. It only gets run once (as the variables are read only and only need to be set once) and since it's a function of the class it can access its private members.

I could add code in the C() constructor that checks to see if the vector is initialized, and initialize it if it's not, but that introduces many necessary checks and doesn't seem like the optimal solution to the problem.

The member is read-only, so it can be static const and I can define it outside the class, but that seems like an ugly hack.

Is it possible to have private static data members in a class if I don't want to initialize them in the instance constructor?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(23

送你一个梦 2024-08-05 23:22:05

要初始化静态变量,只需在源文件内执行此操作即可。 例如:

//Foo.h
class Foo
{
 private:
  static int hello;
};


//Foo.cpp
int Foo::hello = 1;

To initialize a static variable, you just do so inside of a source file. For example:

//Foo.h
class Foo
{
 private:
  static int hello;
};


//Foo.cpp
int Foo::hello = 1;
雪若未夕 2024-08-05 23:22:05

创建一个模板来模仿 C# 的行为怎么样?

template<class T> class StaticConstructor
{
    bool m_StaticsInitialised = false;

public:
    typedef void (*StaticCallback)(void);

    StaticConstructor(StaticCallback callback)
    {
        if (m_StaticsInitialised)
            return;

        callback();

        m_StaticsInitialised = true;
    }
}

template<class T> bool StaticConstructor<T>::m_StaticsInitialised;

class Test : public StaticConstructor<Test>
{
    static std::vector<char> letters_;

    static void _Test()
    {
        for (char c = 'a'; c <= 'z'; c++)
            letters_.push_back(c);
    }

public:
    Test() : StaticConstructor<Test>(&_Test)
    {
        // non static stuff
    };
};

How about creating a template to mimic the behavior of C#.

template<class T> class StaticConstructor
{
    bool m_StaticsInitialised = false;

public:
    typedef void (*StaticCallback)(void);

    StaticConstructor(StaticCallback callback)
    {
        if (m_StaticsInitialised)
            return;

        callback();

        m_StaticsInitialised = true;
    }
}

template<class T> bool StaticConstructor<T>::m_StaticsInitialised;

class Test : public StaticConstructor<Test>
{
    static std::vector<char> letters_;

    static void _Test()
    {
        for (char c = 'a'; c <= 'z'; c++)
            letters_.push_back(c);
    }

public:
    Test() : StaticConstructor<Test>(&_Test)
    {
        // non static stuff
    };
};
在巴黎塔顶看东京樱花 2024-08-05 23:22:05

对于像这里这样的简单情况,包装在静态成员函数内的静态变量几乎同样好。 它很简单,通常会被编译器优化掉。 但这并不能解决复杂对象的初始化顺序问题。

#include <iostream>

class MyClass 
{

    static const char * const letters(void){
        static const char * const var = "abcdefghijklmnopqrstuvwxyz";
        return var;
    }

    public:
        void show(){
            std::cout << letters() << "\n";
        }
};


int main(){
    MyClass c;
    c.show();
}

For simple cases like here a static variable wrapped inside a static member function is nearly as good. It's simple and will usually be optimized away by compilers. This does not solve initialization order problem for complex objects though.

#include <iostream>

class MyClass 
{

    static const char * const letters(void){
        static const char * const var = "abcdefghijklmnopqrstuvwxyz";
        return var;
    }

    public:
        void show(){
            std::cout << letters() << "\n";
        }
};


int main(){
    MyClass c;
    c.show();
}
绝對不後悔。 2024-08-05 23:22:05

这是一个解决方案吗?

class Foo
{
public:
    size_t count;
    Foo()
    {
        static size_t count = 0;
        this->count = count += 1;
    }
};

Is this a solution?

class Foo
{
public:
    size_t count;
    Foo()
    {
        static size_t count = 0;
        this->count = count += 1;
    }
};
小糖芽 2024-08-05 23:22:05

可以使用友元类或嵌套类来模拟静态构造函数,如下所示。

class ClassStatic{
private:
    static char *str;
public:
    char* get_str() { return str; }
    void set_str(char *s) { str = s; }
    // A nested class, which used as static constructor
    static class ClassInit{
    public:
        ClassInit(int size){ 
            // Static constructor definition
            str = new char[size];
            str = "How are you?";
        }
    } initializer;
};

// Static variable creation
char* ClassStatic::str; 
// Static constructor call
ClassStatic::ClassInit ClassStatic::initializer(20);

int main() {
    ClassStatic a;
    ClassStatic b;
    std::cout << "String in a: " << a.get_str() << std::endl;
    std::cout << "String in b: " << b.get_str() << std::endl;
    a.set_str("I am fine");
    std::cout << "String in a: " << a.get_str() << std::endl;
    std::cout << "String in b: " << b.get_str() << std::endl;
    std::cin.ignore();
}

输出:

String in a: How are you?
String in b: How are you?
String in a: I am fine
String in b: I am fine

A static constructor can be emulated by using a friend class or nested class as below.

class ClassStatic{
private:
    static char *str;
public:
    char* get_str() { return str; }
    void set_str(char *s) { str = s; }
    // A nested class, which used as static constructor
    static class ClassInit{
    public:
        ClassInit(int size){ 
            // Static constructor definition
            str = new char[size];
            str = "How are you?";
        }
    } initializer;
};

// Static variable creation
char* ClassStatic::str; 
// Static constructor call
ClassStatic::ClassInit ClassStatic::initializer(20);

int main() {
    ClassStatic a;
    ClassStatic b;
    std::cout << "String in a: " << a.get_str() << std::endl;
    std::cout << "String in b: " << b.get_str() << std::endl;
    a.set_str("I am fine");
    std::cout << "String in a: " << a.get_str() << std::endl;
    std::cout << "String in b: " << b.get_str() << std::endl;
    std::cin.ignore();
}

Output:

String in a: How are you?
String in b: How are you?
String in a: I am fine
String in b: I am fine
八巷 2024-08-05 23:22:05

我使用这种技术来初始化静态内容:
在.cpp文件中:

struct InitMe {
    InitMe(){
        // do all the static stuff you want here
    }
} initMe;

因为它在编译单元中,所以变量initMe将具有程序生命周期。 构造函数将在 main() 之前初始化,析构函数(如果有)将在程序终止之前调用。
与所有静态内容一样,无法保证其执行顺序,但在单个 .cpp 文件中,可以保证静态内容将按照它们在文件中出现的顺序进行初始化。

I use this technique to init static stuff :
In the .cpp file :

struct InitMe {
    InitMe(){
        // do all the static stuff you want here
    }
} initMe;

Because it's in a compilation unit, the variable initMe will have a program lifetime. The constructor will be initialized before main(), and the destructor, if any, will be called before program termination.
Like all static stuff, there's no guarantee on the order it will be executed, but in a single .cpp file, there's a guarantee that static stuff will be initialized in order they appear in the file.

不气馁 2024-08-05 23:22:04

这是另一种方法,其中向量对于包含使用匿名命名空间的实现的文件来说是私有的。 它对于诸如实现私有的查找表之类的东西很有用:

#include <iostream>
#include <vector>
using namespace std;

namespace {
  vector<int> vec;

  struct I { I() {
    vec.push_back(1);
    vec.push_back(3);
    vec.push_back(5);
  }} i;
}

int main() {

  vector<int>::const_iterator end = vec.end();
  for (vector<int>::const_iterator i = vec.begin();
       i != end; ++i) {
    cout << *i << endl;
  }

  return 0;
}

Here's another method, where the vector is private to the file that contains the implementation by using an anonymous namespace. It's useful for things like lookup tables that are private to the implementation:

#include <iostream>
#include <vector>
using namespace std;

namespace {
  vector<int> vec;

  struct I { I() {
    vec.push_back(1);
    vec.push_back(3);
    vec.push_back(5);
  }} i;
}

int main() {

  vector<int>::const_iterator end = vec.end();
  for (vector<int>::const_iterator i = vec.begin();
       i != end; ++i) {
    cout << *i << endl;
  }

  return 0;
}
雨轻弹 2024-08-05 23:22:04

它当然不需要像当前接受的答案(丹尼尔·厄威克)那么复杂。 班级是多余的。 在这种情况下,没有必要进行语言战争。

.hpp 文件:

vector<char> const & letters();

.cpp 文件:

vector<char> const & letters()
{
  static vector<char> v = {'a', 'b', 'c', ...};
  return v;
}

It certainly doesn't need to be as complicated as the currently accepted answer (by Daniel Earwicker). The class is superfluous. There's no need for a language war in this case.

.hpp file:

vector<char> const & letters();

.cpp file:

vector<char> const & letters()
{
  static vector<char> v = {'a', 'b', 'c', ...};
  return v;
}
半寸时光 2024-08-05 23:22:04

GCC 提供

__attribute__((constructor))

https://gcc.gnu.org/ onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html

使用此属性标记静态方法,它将在 main() 之前的模块加载时运行。

GCC offers

__attribute__((constructor))

https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html

Tag a static method with this attribute and it will run on module load, before main().

半衾梦 2024-08-05 23:22:04

定义静态成员变量的方式与定义成员方法的方式类似。

foo.h

class Foo
{
public:
    void bar();
private:
    static int count;
};

foo.cpp

#include "foo.h"

void Foo::bar()
{
    // method definition
}

int Foo::count = 0;

You define static member variables similarly to the way you define member methods.

foo.h

class Foo
{
public:
    void bar();
private:
    static int count;
};

foo.cpp

#include "foo.h"

void Foo::bar()
{
    // method definition
}

int Foo::count = 0;
樱花细雨 2024-08-05 23:22:03

我想这个问题的简单解决方案是:

    //X.h
    #pragma once
    class X
    {
    public:
            X(void);
            ~X(void);
    private:
            static bool IsInit;
            static bool Init();
    };

    //X.cpp
    #include "X.h"
    #include <iostream>

    X::X(void)
    {
    }


    X::~X(void)
    {
    }

    bool X::IsInit(Init());
    bool X::Init()
    {
            std::cout<< "ddddd";
            return true;
    }

    // main.cpp
    #include "X.h"
    int main ()
    {
            return 0;
    }

I guess Simple solution to this will be:

    //X.h
    #pragma once
    class X
    {
    public:
            X(void);
            ~X(void);
    private:
            static bool IsInit;
            static bool Init();
    };

    //X.cpp
    #include "X.h"
    #include <iostream>

    X::X(void)
    {
    }


    X::~X(void)
    {
    }

    bool X::IsInit(Init());
    bool X::Init()
    {
            std::cout<< "ddddd";
            return true;
    }

    // main.cpp
    #include "X.h"
    int main ()
    {
            return 0;
    }
苏辞 2024-08-05 23:22:03

哇,我不敢相信没有人提到最明显的答案,以及最接近 C# 静态构造函数行为的答案,即在创建该类型的第一个对象之前不会调用它。

std::call_once() 在 C++11 中可用; 如果您不能使用它,可以使用静态布尔类变量和比较和交换原子操作来完成。 在构造函数中,查看是否可以自动将类静态标志从 false 更改为 true,如果可以,则可以运行静态构造代码。

为了获得额外的分数,请将其设置为 3 路标志而不是布尔值,即未运行、正在运行和完成运行。 然后该类的所有其他实例都可以自旋锁,直到运行静态构造函数的实例完成(即发出内存栅栏,然后将状态设置为“完成运行”)。 你的自旋锁应该执行处理器的“暂停”指令,每次等待时间加倍,直到达到阈值,等等——相当标准的自旋锁技术。

在没有 C++11 的情况下, 这个 应该得到你开始了。

这里有一些伪代码来指导您。 将其放入您的类定义中:

enum EStaticConstructor { kNotRun, kRunning, kDone };
static volatile EStaticConstructor sm_eClass = kNotRun;

将其放入您的构造函数中:

while (sm_eClass == kNotRun)
{
    if (atomic_compare_exchange_weak(&sm_eClass, kNotRun, kRunning))
    {
        /* Perform static initialization here. */

        atomic_thread_fence(memory_order_release);
        sm_eClass = kDone;
    }
}
while (sm_eClass != kDone)
    atomic_pause();

Wow, I can't believe no one mentioned the most obvious answer, and one that most closely mimics C#'s static-constructor behavior, i.e. it doesn't get called until the first object of that type is created.

std::call_once() is available in C++11; if you can't use that, it can be done with a static boolean class-variable, and a compare-and-exchange atomic-operation. In your constructor, see if you can atomically change the class-static flag from false to true, and if so, you can run the static-construction code.

For extra credit, make it a 3-way flag instead of a boolean, i.e. not run, running, and done running. Then all other instances of that class can spin-lock until the instance running the static-constructor has finished (i.e. issue a memory-fence, then set the state to "done running"). Your spin-lock should execute the processor's "pause" instruction, double the wait each time up until a threshold, etc. — pretty standard spin-locking technique.

In the absence of C++11, this should get you started.

Here's some pseudocode to guide you. Put this in your class definition:

enum EStaticConstructor { kNotRun, kRunning, kDone };
static volatile EStaticConstructor sm_eClass = kNotRun;

And this in your constructor:

while (sm_eClass == kNotRun)
{
    if (atomic_compare_exchange_weak(&sm_eClass, kNotRun, kRunning))
    {
        /* Perform static initialization here. */

        atomic_thread_fence(memory_order_release);
        sm_eClass = kDone;
    }
}
while (sm_eClass != kDone)
    atomic_pause();
心欲静而疯不止 2024-08-05 23:22:03

刚刚解决了同样的技巧。 我必须为 Singleton 指定单个静态成员的定义。
但让事情变得更复杂 - 我决定我不想调用 RandClass() 的 ctor 除非我要使用它......这就是为什么我不想在我的代码中全局初始化单例。 我还在我的案例中添加了简单的界面。

这是最终的代码:

我简化了代码并使用 rand() 函数及其单种子初始值设定项 srand()

interface IRandClass
{
 public:
    virtual int GetRandom() = 0;
};

class RandClassSingleton
{
private:
  class RandClass : public IRandClass
  {
    public:
      RandClass()
      {
        srand(GetTickCount());
      };

     virtual int GetRandom(){return rand();};
  };

  RandClassSingleton(){};
  RandClassSingleton(const RandClassSingleton&);

  // static RandClass m_Instance;

  // If you declare m_Instance here you need to place
  // definition for this static object somewhere in your cpp code as
  // RandClassSingleton::RandClass RandClassSingleton::m_Instance;

  public:

  static RandClass& GetInstance()
  {
      // Much better to instantiate m_Instance here (inside of static function).
      // Instantiated only if this function is called.

      static RandClass m_Instance;
      return m_Instance;
  };
};

main()
{
    // Late binding. Calling RandClass ctor only now
    IRandClass *p = &RandClassSingleton::GetInstance();
    int randValue = p->GetRandom();
}
abc()
{
    IRandClass *same_p = &RandClassSingleton::GetInstance();
}

Just solved same trick. I had to specify definition of a single static member for Singleton.
But make things more complicated - I have decided that I do not want to call ctor of RandClass() unless I am gonna use it... that is why I did not want to initialize singleton globally in my code. Also I've added simple interface in my case.

Here is the final code:

I simplified code and use rand() function and its single seed initialzer srand()

interface IRandClass
{
 public:
    virtual int GetRandom() = 0;
};

class RandClassSingleton
{
private:
  class RandClass : public IRandClass
  {
    public:
      RandClass()
      {
        srand(GetTickCount());
      };

     virtual int GetRandom(){return rand();};
  };

  RandClassSingleton(){};
  RandClassSingleton(const RandClassSingleton&);

  // static RandClass m_Instance;

  // If you declare m_Instance here you need to place
  // definition for this static object somewhere in your cpp code as
  // RandClassSingleton::RandClass RandClassSingleton::m_Instance;

  public:

  static RandClass& GetInstance()
  {
      // Much better to instantiate m_Instance here (inside of static function).
      // Instantiated only if this function is called.

      static RandClass m_Instance;
      return m_Instance;
  };
};

main()
{
    // Late binding. Calling RandClass ctor only now
    IRandClass *p = &RandClassSingleton::GetInstance();
    int randValue = p->GetRandom();
}
abc()
{
    IRandClass *same_p = &RandClassSingleton::GetInstance();
}
请帮我爱他 2024-08-05 23:22:03

这是我的 EFraim 解决方案的变体; 区别在于,由于隐式模板实例化,只有创建类的实例时才会调用静态构造函数,并且不需要在 .cpp 文件中进行定义(感谢模板实例化魔法) 。

.h 文件中,您可以:

template <typename Aux> class _MyClass
{
    public:
        static vector<char> a;
        _MyClass() {
            (void) _initializer; //Reference the static member to ensure that it is instantiated and its initializer is called.
        }
    private:
        static struct _init
        {
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;

};
typedef _MyClass<void> MyClass;

template <typename Aux> vector<char> _MyClass<Aux>::a;
template <typename Aux> typename _MyClass<Aux>::_init _MyClass<Aux>::_initializer;

.cpp 文件中,您可以:

void foobar() {
    MyClass foo; // [1]

    for (vector<char>::iterator it = MyClass::a.begin(); it < MyClass::a.end(); ++it) {
        cout << *it;
    }
    cout << endl;
}

请注意,仅当满足以下条件时,MyClass::a 才会被初始化:第 [1] 行在那里,因为它调用(并需要实例化)构造函数,然后需要实例化 _initializer

Here's my variant of EFraim's solution; the difference is that, thanks to implicit template instantiation, the static constructor is only called if instances of the class are created, and that no definition in the .cpp file is needed (thanks to template instantiation magic).

In the .h file, you have:

template <typename Aux> class _MyClass
{
    public:
        static vector<char> a;
        _MyClass() {
            (void) _initializer; //Reference the static member to ensure that it is instantiated and its initializer is called.
        }
    private:
        static struct _init
        {
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;

};
typedef _MyClass<void> MyClass;

template <typename Aux> vector<char> _MyClass<Aux>::a;
template <typename Aux> typename _MyClass<Aux>::_init _MyClass<Aux>::_initializer;

In the .cpp file, you can have:

void foobar() {
    MyClass foo; // [1]

    for (vector<char>::iterator it = MyClass::a.begin(); it < MyClass::a.end(); ++it) {
        cout << *it;
    }
    cout << endl;
}

Note that MyClass::a is initialized only if line [1] is there, because that calls (and requires instantiation of) the constructor, which then requires instantiation of _initializer.

初见终念 2024-08-05 23:22:02

Java 吸取了 C++ 的问题后,引入了静态构造函数的概念。 所以我们没有直接的等价物。

最好的解决方案是使用可以显式初始化的 POD 类型。
或者使您的静态成员成为具有自己的构造函数的特定类型,该构造函数可以正确初始化它。

//header

class A
{
    // Make sure this is private so that nobody can missues the fact that
    // you are overriding std::vector. Just doing it here as a quicky example
    // don't take it as a recomendation for deriving from vector.
    class MyInitedVar: public std::vector<char>
    {
        public:
        MyInitedVar()
        {
           // Pre-Initialize the vector.
           for(char c = 'a';c <= 'z';++c)
           {
               push_back(c);
           }
        }
    };
    static int          count;
    static MyInitedVar  var1;

};


//source
int            A::count = 0;
A::MyInitedVar A::var1;

The concept of static constructors was introduced in Java after they learned from the problems in C++. So we have no direct equivalent.

The best solution is to use POD types that can be initialised explicitly.
Or make your static members a specific type that has its own constructor that will initialize it correctly.

//header

class A
{
    // Make sure this is private so that nobody can missues the fact that
    // you are overriding std::vector. Just doing it here as a quicky example
    // don't take it as a recomendation for deriving from vector.
    class MyInitedVar: public std::vector<char>
    {
        public:
        MyInitedVar()
        {
           // Pre-Initialize the vector.
           for(char c = 'a';c <= 'z';++c)
           {
               push_back(c);
           }
        }
    };
    static int          count;
    static MyInitedVar  var1;

};


//source
int            A::count = 0;
A::MyInitedVar A::var1;
ㄟ。诗瑗 2024-08-05 23:22:02

当尝试编译和使用Elsewhere时(来自Earwicker 的回答)我得到:

error LNK2001: unresolved external symbol "private: static class StaticStuff Elsewhere::staticStuff" (?staticStuff@Elsewhere@@0VStaticStuff@@A)

似乎不可能在不将一些代码放在类定义之外的情况下初始化非整数类型的静态属性(CPP )。

要进行编译,您可以使用“内部带有静态局部变量的静态方法”。 像这样的事情:

class Elsewhere
{
public:
    static StaticStuff& GetStaticStuff()
    {
        static StaticStuff staticStuff; // constructor runs once, single instance
        return staticStuff;
    }
};

你还可以将参数传递给构造函数或用特定值初始化它,它非常灵活,强大且易于实现......唯一的事情是你有一个包含静态变量的静态方法,而不是静态属性...语法略有变化,但仍然有用。 希望这对雨果·冈萨雷斯·卡斯特罗(Hugo González Castro)有用

When trying to compile and use class Elsewhere (from Earwicker's answer) I get:

error LNK2001: unresolved external symbol "private: static class StaticStuff Elsewhere::staticStuff" (?staticStuff@Elsewhere@@0VStaticStuff@@A)

It seems is not possible to initialize static attributes of non-integer types without putting some code outside the class definition (CPP).

To make that compile you can use "a static method with a static local variable inside" instead. Something like this:

class Elsewhere
{
public:
    static StaticStuff& GetStaticStuff()
    {
        static StaticStuff staticStuff; // constructor runs once, single instance
        return staticStuff;
    }
};

And you may also pass arguments to the constructor or initialize it with specific values, it is very flexible, powerfull and easy to implement... the only thing is you have a static method containing a static variable, not a static attribute... syntaxis changes a bit, but still useful. Hope this is useful for someone,

Hugo González Castro.

云醉月微眠 2024-08-05 23:22:01

Test::StaticTest() 在全局静态初始化期间仅调用一次。

调用者只需向函数添加一行即可作为其静态构造函数。

static_constructor<&Test::StaticTest>::c; 在全局静态初始化期间强制初始化 c

template<void(*ctor)()>
struct static_constructor
{
    struct constructor { constructor() { ctor(); } };
    static constructor c;
};

template<void(*ctor)()>
typename static_constructor<ctor>::constructor static_constructor<ctor>::c;

/////////////////////////////

struct Test
{
    static int number;

    static void StaticTest()
    {
        static_constructor<&Test::StaticTest>::c;

        number = 123;
        cout << "static ctor" << endl;
    }
};

int Test::number;

int main(int argc, char *argv[])
{
    cout << Test::number << endl;
    return 0;
}

Test::StaticTest() is called exactly once during global static initialization.

Caller only has to add one line to the function that is to be their static constructor.

static_constructor<&Test::StaticTest>::c; forces initialization of c during global static initialization.

template<void(*ctor)()>
struct static_constructor
{
    struct constructor { constructor() { ctor(); } };
    static constructor c;
};

template<void(*ctor)()>
typename static_constructor<ctor>::constructor static_constructor<ctor>::c;

/////////////////////////////

struct Test
{
    static int number;

    static void StaticTest()
    {
        static_constructor<&Test::StaticTest>::c;

        number = 123;
        cout << "static ctor" << endl;
    }
};

int Test::number;

int main(int argc, char *argv[])
{
    cout << Test::number << endl;
    return 0;
}
深海夜未眠 2024-08-05 23:22:01

不需要 init() 函数,可以从范围创建 std::vector

// h file:
class MyClass {
    static std::vector<char> alphabet;
// ...
};

// cpp file:
#include <boost/range.hpp>
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
std::vector<char> MyClass::alphabet( boost::begin( ::alphabet ), boost::end( ::alphabet ) );

但是请注意,类类型的静态会在库中引起麻烦,因此它们应该避免那里。

C++11 更新

从 C++11 开始,您可以这样做:

// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };

它在语义上等同于原始答案中的 C++98 解决方案,但您不能在右侧,所以它并不完全优越。 但是,如果您有除 charwchar_tchar16_tchar32_t 以外的任何其他类型的向量(数组可以写成字符串文字),与 C++98 版本相比,C++11 版本将严格删除样板代码,而不引入其他语法。

No need for an init() function, std::vector can be created from a range:

// h file:
class MyClass {
    static std::vector<char> alphabet;
// ...
};

// cpp file:
#include <boost/range.hpp>
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
std::vector<char> MyClass::alphabet( boost::begin( ::alphabet ), boost::end( ::alphabet ) );

Note, however, that statics of class type cause trouble in libraries, so they should be avoided there.

C++11 Update

As of C++11, you can do this instead:

// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };

It's semantically equivalent to the C++98 solution in the original answer, but you can't use a string literal on the right-hand-side, so it's not completely superior. However, if you have a vector of any other type than char, wchar_t, char16_t or char32_t (arrays of which can be written as string literals), the C++11 version will strictly remove boilerplate code without introducing other syntax, compared to the C++98 version.

冧九 2024-08-05 23:22:00

在 .h 文件中:

class MyClass {
private:
    static int myValue;
};

在 .cpp 文件中:

#include "myclass.h"

int MyClass::myValue = 0;

In the .h file:

class MyClass {
private:
    static int myValue;
};

In the .cpp file:

#include "myclass.h"

int MyClass::myValue = 0;
梦初启 2024-08-05 23:22:00

这是与 Daniel Earwicker 类似的另一种方法,也使用 Konrad Rudolph 的朋友类建议。 这里我们使用内部私有友元实用程序类来初始化主类的静态成员。 例如:

头文件:

class ToBeInitialized
{
    // Inner friend utility class to initialize whatever you need

    class Initializer
    {
    public:
        Initializer();
    };

    friend class Initializer;

    // Static member variables of ToBeInitialized class

    static const int numberOfFloats;
    static float *theFloats;

    // Static instance of Initializer
    //   When this is created, its constructor initializes
    //   the ToBeInitialized class' static variables

    static Initializer initializer;
};

实现文件:

// Normal static scalar initializer
const int ToBeInitialized::numberOfFloats = 17;

// Constructor of Initializer class.
//    Here is where you can initialize any static members
//    of the enclosing ToBeInitialized class since this inner
//    class is a friend of it.

ToBeInitialized::Initializer::Initializer()
{
    ToBeInitialized::theFloats =
        (float *)malloc(ToBeInitialized::numberOfFloats * sizeof(float));

    for (int i = 0; i < ToBeInitialized::numberOfFloats; ++i)
        ToBeInitialized::theFloats[i] = calculateSomeFancyValue(i);
}

这种方法的优点是对外界完全隐藏Initializer 类,保持类中包含的所有内容都被初始化。

Here is another approach similar to Daniel Earwicker's, also using Konrad Rudolph's friend class suggestion. Here we use an inner private friend utility class to initialize the static members of your main class. For example:

Header file:

class ToBeInitialized
{
    // Inner friend utility class to initialize whatever you need

    class Initializer
    {
    public:
        Initializer();
    };

    friend class Initializer;

    // Static member variables of ToBeInitialized class

    static const int numberOfFloats;
    static float *theFloats;

    // Static instance of Initializer
    //   When this is created, its constructor initializes
    //   the ToBeInitialized class' static variables

    static Initializer initializer;
};

Implementation file:

// Normal static scalar initializer
const int ToBeInitialized::numberOfFloats = 17;

// Constructor of Initializer class.
//    Here is where you can initialize any static members
//    of the enclosing ToBeInitialized class since this inner
//    class is a friend of it.

ToBeInitialized::Initializer::Initializer()
{
    ToBeInitialized::theFloats =
        (float *)malloc(ToBeInitialized::numberOfFloats * sizeof(float));

    for (int i = 0; i < ToBeInitialized::numberOfFloats; ++i)
        ToBeInitialized::theFloats[i] = calculateSomeFancyValue(i);
}

This approach has the advantage of completely hiding the Initializer class from the outside world, keeping everything contained within the class to be initialized.

玩物 2024-08-05 23:21:59

好吧,你可以

class MyClass
{
    public:
        static vector<char> a;

        static class _init
        {
          public:
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;
};

不要忘记(在 .cpp 中):

vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;

程序仍然会在没有第二行的情况下链接,但初始化程序不会被执行。

Well you can have

class MyClass
{
    public:
        static vector<char> a;

        static class _init
        {
          public:
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;
};

Don't forget (in the .cpp) this:

vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;

The program will still link without the second line, but the initializer will not be executed.

愁以何悠 2024-08-05 23:21:59

C++17

从 C++17 开始,您可以使用 lambda 初始化复杂的静态数据成员表达式并声明它们内联

class MyClass {
    inline static const std::vector<char> letters = [] {
        std::vector<char> letters;
        for (char c = 'a'; c <= 'z'; c++)
            letters.push_back(c);
        return letters;
    }();
};

C++11

自C ++11,您可以使用 lambda 表达式 初始化复杂的静态数据成员:

头文件:

class MyClass {
    static const std::vector<char> letters;
};

源文件:

const std::vector<char> MyClass::letters = [] {
    std::vector<char> letters;
    for (char c = 'a'; c <= 'z'; c++)
        letters.push_back(c);
    return letters;
}();

C++17

Since C++17, you can initialize complex static data members by using lambda expressions and declaring them inline:

class MyClass {
    inline static const std::vector<char> letters = [] {
        std::vector<char> letters;
        for (char c = 'a'; c <= 'z'; c++)
            letters.push_back(c);
        return letters;
    }();
};

C++11

Since C++11, you can initialize complex static data members by using lambda expressions:

Header file:

class MyClass {
    static const std::vector<char> letters;
};

Source file:

const std::vector<char> MyClass::letters = [] {
    std::vector<char> letters;
    for (char c = 'a'; c <= 'z'; c++)
        letters.push_back(c);
    return letters;
}();
不打扰别人 2024-08-05 23:21:58

要获得静态构造函数的等效项,您需要编写一个单独的普通类来保存静态数据,然后创建该普通类的静态实例。

class StaticStuff
{
     std::vector<char> letters_;

public:
     StaticStuff()
     {
         for (char c = 'a'; c <= 'z'; c++)
             letters_.push_back(c);
     }

     // provide some way to get at letters_
};

class Elsewhere
{
    static StaticStuff staticStuff; // constructor runs once, single instance

};

To get the equivalent of a static constructor, you need to write a separate ordinary class to hold the static data and then make a static instance of that ordinary class.

class StaticStuff
{
     std::vector<char> letters_;

public:
     StaticStuff()
     {
         for (char c = 'a'; c <= 'z'; c++)
             letters_.push_back(c);
     }

     // provide some way to get at letters_
};

class Elsewhere
{
    static StaticStuff staticStuff; // constructor runs once, single instance

};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文