首页 > 解决方案 > 有没有办法在构造函数代码中初始化类的成员对象而不是初始化列表?

问题描述

考虑我想在一个对象中包装一些库代码。该库需要通过调用该包装类的构造函数中的某个函数来设置和初始化。

图书馆的“对象”然后分散到创建更多不同的“对象”,包装类以另一个包装对象的形式包装,该对象应该是该类的普通成员。

但在我看来,类的成员只能通过在构造函数的初始化列表中调用它们的构造函数来初始化或创建。这些代码位的执行先于执行库及其环境初始化的实际类的构造函数,这使我无法将该成员对象实际初始化为成员,而是强制我将其初始化为指向第二个包装器,因为它的构造器必须在第一个构造器的代码中手动调用。

例子:

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

标签: c++memoryconstructormember

解决方案


成员对象只能在成员初始化器列表中构造。不过,有一些技术可用于初始化对象:

  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();
        }
        // ...
    };
    

我个人会使用第一种方法。但是,在某些情况下,使用 aunion来延迟构造是有帮助的。


推荐阅读