Есть ли способ инициализировать объект-член класса в коде конструкторов вместо списка инициализаторов? - PullRequest
0 голосов
/ 27 декабря 2018

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

Затем «объекты» библиотеки будут расходиться, создавая больше разных «объектов», которые класс-оболочка оборачивает в видееще один объект-обертка, который должен быть простым членом этого класса.

Но, насколько я понимаю, члены классов могут быть инициализированы или созданы только путем вызова их конструктора в списке инициализатора конструктора.Выполнение этих битов кода предшествовало конструктору фактического класса, который выполняет инициализацию библиотеки и ее среды, что делает для меня невозможной фактическую инициализацию этого объекта-члена как члена и вместо этого вынуждает меня инициализировать его как указатель навторая обертка, потому что ее конструктор должен вызываться вручную в коде первого конструктора.

Пример:

class A {
public:
    A() {
        if(!wrapped_library_init()) {
            exit(CRITICAL_ERROR);
        }
        ptr_to_some_library_metadata *a = library_function(); /*Needs to
        be called after wrapped_library_init() or needs a pointer to some
        wrapped object created inside this constructor */
        //initialize b
    }
private:
    B b; //Wants to be a member but can not
};

class B {
    B(ptr_to_some_library_metadata *a);
}

Ответы [ 3 ]

0 голосов
/ 27 декабря 2018

Объекты-члены могут создаваться только в списке инициализаторов элементов.Существует несколько методов, которые можно использовать для инициализации объекта:

  1. Используйте вспомогательную функцию [lambda], выполняющую необходимую дополнительную работу перед возвратом подходящего объекта.Например:

    A()
          : B([]{
              if (!wrapped_library_init()) {
                  exit(CRITICAL_ERROR);
              }
              return library_function();
          }()) {
    }
    
  2. Вы можете отложить построение, используя union только с соответствующим членом.При использовании этой техники элемент должен быть явно уничтожен, например:

    class A {
        union Bu { B b };
        Bu b;
    public:
        A() {
            if (!wrapped_library_init()) {
                exit(CRITICAL_ERROR);
            }
            new(&b.b) B(library_function());
        }
        ~A() {
            b.b.~B();
        }
        // ...
    };
    

Я бы лично использовал первый подход.Однако в некоторых случаях полезно использовать union для задержки построения.

0 голосов
/ 27 декабря 2018

Оберните вашу библиотеку внутри класса:

class LibraryWrapper
{
public:
    LibraryWrapper()
    {
        if(!wrapped_library_init()) {
            exit(CRITICAL_ERROR);
        }
        lib_data.reset(library_function()); /*Needs to
        be called after wrapped_library_init() or needs a pointer to some
        wrapped object created inside this constructor */
    }
    //~LibraryWrapper() {/**/}
    //LibraryWrapper(const LibraryWrapper&) {/**/}            // =delete; ?
    //LibraryWrapper& operator=(const LibraryWrapper&) {/**/} // =delete; ?

//private: // and appropriate interface to hide internal
    std::unique_ptr<ptr_to_some_library_metadata, CustomDeleter> lib_data;
};

class B {
public:
    explicit B(ptr_to_some_library_metadata *a);
    // ...
};

И используйте дополнительный член или наследование:

class A
{
public:
    A() : b(lib.lib_data.get()) {}
private:
    LibraryWrapper lib; // placed before B
    B b;
};
0 голосов
/ 27 декабря 2018

В списках инициализаторов можно использовать конструктор, отличный от конструктора по умолчанию.

Но ничто не мешает вам создать пользовательскую функцию, которая будет инициализировать b:

class A {
public:
    A():b(init()) {
    }
private:
    B b; //Wants to be a member but can not

    static B init()
    {
        if(!wrapped_library_init()) {
            exit(CRITICAL_ERROR);
        }
        ptr_to_some_library_metadata *a = library_function(); /*Needs to
        be called after wrapped_library_init() or needs a pointer to some
        wrapped object created inside this constructor */

        return B(a);
    }
};
...