185

プライベート静的データメンバー(すべての文字azを含むベクトル)を持つクラスが必要です。JavaまたはC#では、クラスのインスタンスを作成する前に実行される「静的コンストラクター」を作成し、クラスの静的データメンバーを設定できます。これは1回だけ実行され(変数は読み取り専用であり、一度だけ設定する必要があるため)、クラスの関数であるため、プライベートメンバーにアクセスできます。ベクトルが初期化されているかどうかを確認するコードをコンストラクターに追加し、初期化されていない場合は初期化することもできますが、必要なチェックが多数発生し、問題の最適な解決策とは思えません。

変数は読み取り専用になるので、public static constにすることができるので、クラスの外で一度設定できますが、もう一度、醜いハックのように思えます。

インスタンスコンストラクターでプライベート静的データメンバーを初期化したくない場合、クラスにプライベート静的データメンバーを含めることは可能ですか?

4

22 に答える 22

186

静的コンストラクターに相当するものを取得するには、別の通常クラスを作成して静的データを保持し、その通常クラスの静的インスタンスを作成する必要があります。

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

};
于 2009-07-28T22:33:12.380 に答える
83

さて、あなたは持つことができます

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;

プログラムは 2 行目なしでもリンクしますが、初期化子は実行されません。

于 2009-07-28T22:37:36.770 に答える
41

C++11 アップデート

C++11 以降、特定の順序で初期化する必要がある場合やconstとして宣言されている場合でも、ラムダ式を使用して静的クラス メンバーを初期化できます。静的メンバーは常に、ソースファイル内で定義されているのとまったく同じ順序で初期化されます。

ヘッダー ファイル:

class MyClass {
    static const vector<char> letters;
    static const size_t letterCount;
};

ソースファイル:

// Initialize MyClass::letters with all letters from 'a' to 'z'.
const vector<char> MyClass::letters = [] {
    vector<char> letters;
    for (char c = 'a'; c <= 'z'; c++) letters.push_back(c);
    return letters;
}();

// Initialize MyClass::letterCount based on MyClass::letters.
const size_t MyClass::letterCount = letters.size();
于 2016-08-09T15:59:50.920 に答える
21

.hファイル内:

class MyClass {
private:
    static int myValue;
};

.cppファイル:

#include "myclass.h"

int MyClass::myValue = 0;
于 2009-07-28T22:29:43.963 に答える
15

これは、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 クラスを外部から完全に隠し、クラス内に含まれるすべてのものを初期化するという利点があります。

于 2011-01-20T00:10:35.147 に答える
12

Test::StaticTest()グローバルな静的初期化中に 1 回だけ呼び出されます。

呼び出し元は、静的コンストラクターとなる関数に 1 行追加するだけです。

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;
}
于 2013-08-25T22:05:45.447 に答える
9

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 ) );

ただし、クラス型の static はライブラリで問題を引き起こすため、ライブラリでは避ける必要があることに注意してください。

C++11 アップデート

C++11 以降では、代わりにこれを行うことができます。

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

元の回答の C++98 ソリューションと意味的に同等ですが、右側で文字列リテラルを使用できないため、完全に優れているわけではありません。charただし、 、wchar_tchar16_tまたはchar32_t(文字列リテラルとして記述できる配列)以外の型のベクトルがある場合、C++11 バージョンは、C++98 と比較して、他の構文を導入することなくボイラープレート コードを厳密に削除します。バージョン。

于 2009-07-29T07:29:09.307 に答える
7

静的コンストラクターの概念は、C++ の問題から学んだ後、Java に導入されました。したがって、直接同等のものはありません。

最善の解決策は、明示的に初期化できる 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;
于 2009-07-28T22:37:50.403 に答える
4

これに対する簡単な解決策は次のようになると思います。

    //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;
    }
于 2013-03-21T05:56:55.247 に答える
4

Earwickerの回答から)クラスをコンパイルして使用しようとすると、次のようになります。Elsewhere

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

また、コンストラクターに引数を渡したり、特定の値で初期化したりすることもできます。これは非常に柔軟で強力で、実装が簡単です...唯一のことは、静的属性ではなく静的変数を含む静的メソッドがあることです...構文は少し変更されますが、それでも便利です。これが誰かに役立つことを願っています、

ヒューゴゴンザレスカストロ。

于 2010-01-28T10:45:44.783 に答える
1

これが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;
}

は、行 [1] がある場合にのみ初期化されることに注意してください。MyClass::aこれは、コンストラクターを呼び出す (およびそのインスタンス化が必要) ためです_initializer

于 2012-01-29T11:31:48.767 に答える
1

匿名の名前空間を使用して、ベクトルが実装を含むファイルに対してプライベートである別の方法を次に示します。実装にプライベートなルックアップ テーブルなどに役立ちます。

#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;
}
于 2012-07-31T16:20:40.613 に答える
1

同じトリックを解決しました。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();
}
于 2012-01-20T21:43:38.850 に答える
0

ここのような単純なケースでは、静的メンバー関数内にラップされた静的変数はほぼ同じくらい良いです。これは単純で、通常はコンパイラーによって最適化されます。ただし、これは複雑なオブジェクトの初期化順序の問題を解決しません。

#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();
}
于 2011-01-20T00:39:50.263 に答える
0

メンバーメソッドを定義する方法と同様に、静的メンバー変数を定義します。

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;
于 2009-07-28T22:30:21.387 に答える
0

静的変数を初期化するには、ソース ファイル内で行うだけです。例えば:

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


//Foo.cpp
int Foo::hello = 1;
于 2009-07-28T22:30:44.287 に答える
0

静的コンストラクターは、以下のようにフレンド クラスまたはネストされたクラスを使用してエミュレートできます。

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
于 2016-06-22T09:18:32.387 に答える
0

これは解決策ですか?

class Foo
{
public:
    size_t count;
    Foo()
    {
        static size_t count = 0;
        this->count = count += 1;
    }
};
于 2011-12-07T15:52:30.970 に答える
0

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
    };
};
于 2009-07-29T08:00:43.410 に答える