2015-11-30 4 views
0

У меня есть статический член класса, который нужно построить с использованием конструктора, отличного от стандартного. Код выглядит так:Построение статической переменной-члена поздно

class MyClass 
{ 
public: 
    static void initialise(int arg1, int arg2) 
    { 
     static MyClass instance(arg1, arg2); 
     _instance = instance; 
    } 

    static MyClass& instance() 
    { 
     return _instance; 
    } 

    /* Other non-static functions used with the return of instance()... */ 

private: 
    MyClass(int arg1, int arg2) 
     : _arg1(arg1), _arg2(arg2) {} 

    static MyClass& _instance; 
    int _arg1, _arg2; 
}; 

Я делаю это, потому что мне нужен один экземпляр класса для жизни приложения, однако она должна быть построена с аргументами, которые известны только после того, как конфигурация была прочитана. Суперкласс MyClass вызовет переопределение в MyClass, которое зависит от знания этих элементов конфигурации.

Я пытался найти способ объявить статический член MyClass, который начинается как просто заполнитель, поэтому его можно построить позже, но мои тесты показывают, что это невозможно. Тест ниже:

#include <cstdio> 

class CNoDefCtor 
{ 
public: 
    CNoDefCtor(int arg1) 
     : _arg1(arg1) 
    { 
     printf("%s\n", __func__); 
    } 

    virtual ~CNoDefCtor() 
    { 
     printf("%s\n", __func__); 
    } 

    static void Initialise(int arg1) 
    { 
     printf("%s\n", __func__); 
     CNoDefCtor _instance(arg1); /* Actually construct here?!? */ 
    } 

    static CNoDefCtor& instance() 
    { 
     return _instance; 
    } 

    int Arg1() 
    { 
     return _arg1; 
    } 

private: 
    int _arg1; 
    static CNoDefCtor _instance; 
}; 

int main() 
{ 
    printf("%s\n", __func__); 

    CNoDefCtor ndc; /* Placeholder? */ 
    ndc.Initialise(1); 
    printf("%d\n", ndc.Instance().Arg1()); 

    printf("%s\n", __func__); 
} 

Так что я думаю, мой вопрос: как вы заявляете, но не построить статический член? Я думал, что если бы у него не было конструктора по умолчанию, это было бы возможно.

Пожалуйста, скажите мне, что я пропустил что-то простое и что есть простой способ сделать это.

+0

Почему бы не держать статический член как указатель (или shared_ptr)? Значение по умолчанию будет NULL, а create() вызовет новый ... – Shloim

+0

Поскольку в любом случае у вас есть функция 'instance()', было бы намного проще сделать фактический объект статической переменной 'instance()' а не статический член класса. – JSF

+0

В зависимости от других деталей ваших требований, я ожидаю, что вы хотите, чтобы единственный конструктор был частным конструктором по умолчанию, который ничего не делает, а затем обрабатывает инициализацию с помощью функции non constructor. – JSF

ответ

1

Что вы здесь делаете, это классический класс Singleton. https://en.wikipedia.org/wiki/Singleton_pattern

Определение класса, которое вы написали в первом блоке кода, является хорошим и должно работать. Статический объект класса будет инициализирован при первом вызове initialise().

Я думаю, что проблема связана с вашим тестовым кодом, вам не нужна переменная держателя места в основном. Это создаст объект вашего одноэлементного класса, которого вы, очевидно, не хотите.

Так короче говоря, чтобы исправить одноплодный класс вы должны соблюдать следующие правила, когда пишет одноэлементный класс,

  1. Конструктора по умолчанию в частном порядке.
  2. Функция инициализации является статической.
  3. Статическая переменная (экземпляр) в определении класса должна быть указателем или ссылочной переменной.

Так что ваше новое определение тестового класса должно выглядеть,

class CNoDefCtor : public CAnnoyingClass 
{ 
private: 
    CNoDefCtor(int arg1) 
     : _arg1(arg1) 
    { 
     printf("%s\n", __func__); 
    } 

public: 
    virtual ~CNoDefCtor() 
    { 
     printf("%s\n", __func__); 
    } 

    static void Initialise(int arg1) 
    { 
     printf("%s\n", __func__); 
     _instance = new CNoDefCtor(arg1); 
    } 

    static CNoDefCtor& instance() 
    { 
     return *_instance; 
    } 

    int Arg1() 
    { 
     return _arg1; 
    } 

private: 
    int _arg1; 
    static CNoDefCtor *_instance; 
}; 

int main() 
{ 
    printf("%s\n", __func__); 

    CNoDefCtor::Initialise(1); 
    printf("%d\n", CNoDefCtor::Instance().Arg1()); 

    printf("%s\n", __func__); 
}