Правильный способ условно инициализировать членскую переменную C++?

Однострочник:

$images = array_map('basename', glob($directory . "*.{jpg,JPG,jpeg,JPEG,png,PNG}", GLOB_BRACE));
11
задан Pedro d'Aquino 18 June 2009 в 19:08
поделиться

6 ответов

Используйте условный оператор. Если выражение больше, используйте функцию

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz == 42 ? 12 : 32) {

    }
};

class MyClass {
    static int classInit(int n) { ... }
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

. Чтобы вызвать функцию перед инициализацией m_class, вы можете поместить структуру перед этим членом и использовать RAII

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            do_something();
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

. Это вызовет do_something () перед инициализацией ] m_class . Обратите внимание, что вам не разрешено вызывать нестатические функции-члены MyClass до завершения списка инициализаторов конструктора. Функция должна быть членом своего базового класса, а ctor базового класса уже должен быть завершен, чтобы это работало.

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

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            static int only_once = (do_something(), 0);
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

It ' s с помощью оператора запятой. Обратите внимание, что вы можете перехватить любое исключение, созданное do_something , используя блок function-try

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            static int only_once = (do_something(), 0);
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) try : m_class(classInit(xyz)) {

    } catch(...) { /* handle exception */ }
};

. Функция do_something будет вызвана снова в следующий раз, если это исключение, вызвавшее Объект MyClass не может быть создан. Надеюсь, это поможет :)

25
ответ дан 3 December 2019 в 02:02
поделиться

Используйте синтаксис списка инициализаторов:

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz == 42 ? MemberClass(12) : MemberClass(32)
                               /* see the comments, cleaner as xyz == 42 ? 12 : 32*/)
    { }
};

Вероятно, более чистый с фабрикой:

MemberClass create_member(int x){
   if(xyz == 42)
     return MemberClass(12);
    // ...
}

//...
 MyClass(int xyz) : m_class(create_member(xyz))
5
ответ дан 3 December 2019 в 02:02
поделиться
 MyClass(int xyz) : m_class(xyz==42 ? 12 : 32) {}

Чтобы ответить на ваш измененный вопрос, это немного сложно. Самый простой способ - сделать m_class указателем. Если вы действительно хотите, чтобы он был членом данных, вам нужно проявить творческий подход. Создайте новый класс (лучше всего, если он будет определен внутри MyClass). Пусть это будет функция, которую нужно вызвать. Включите его первым среди объявлений членов данных (это сделает его первым экземпляром).

class MyClass 
{
     class initer { public: initer() {
                    // this must happen before m_class is created
                    do_something();                        
                    }
                   }

    initer     dummy;
public:

    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz==42? 12 : 43)
    {
        // dummy silently default ctor'ed before m_class.
    }
};
5
ответ дан 3 December 2019 в 02:02
поделиться

Попробуйте следующее:

class MemberClass
{
public:    
   MemberClass(int abc = 0){ }
};

Это даст ему значение по умолчанию и ваш конструктор по умолчанию.

0
ответ дан 3 December 2019 в 02:02
поделиться

Или:

class MemberClass {
public:
    MemberClass(int abc){ }
};

class MyClass {
public:
    MemberClass* m_class;
    MyClass(int xyz) {
        if(xyz == 42)
            m_class = new MemberClass(12);
        else
            m_class = new MemberClass(32);
    }
};

Если вы каким-то образом хотите сохранить тот же синтаксис. Однако инициализация членов более эффективна.

0
ответ дан 3 December 2019 в 02:02
поделиться

Чтобы инициализация происходила после других событий, вам действительно нужно использовать указатели, примерно так:

class MyClass {
public:
    MemberClass * m_pClass;
    MyClass(int xyz) {
        do_something(); // this must happen before m_class is created
        if(xyz == 42)
            m_pClass = new MemberClass(12);
        else
            m_pClass = new MemberClass(32);
    }
};

Единственное отличие состоит в том, что вам нужно будет обращаться к переменным-членам как m_pClass-> counter вместо m_class.counter и удалить m_pClass в деструкторе.

0
ответ дан 3 December 2019 в 02:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: