如何定义带有成员初始值设定项列表的构造函数,其中初始化非常复杂

问题描述 投票:0回答:4

假设我想要一个接收一些参数的构造函数,并且通过这些参数我可以计算它的成员变量的值。除了成员变量的值不是来自参数的简单赋值之外。它们需要创建其他对象并转换值才能用作成员变量的值。

将这种方式塞进初始值设定项列表中的方式太多了。而且效率非常低,因为您无法创建变量并重用它们,因此您必须复制代码(并制作同一对象的多个副本)以适应初始值设定项列表中的所有代码。

另一种选择是不使用初始化列表并让默认构造函数被调用,然后用简洁的计算覆盖构造函数内的值。

现在如果类没有默认构造函数怎么办?怎样才能巧妙地做到这一点?

/* a class without a default constructor */
struct A {
    B x1
    B x2
    A(B x1_, B x2_) : x1{x1_}, x2{x2_} {}
};

struct C {
    A a;
    C(D d) : a{/* very complicated */, /* very complicated */} {}
};

最终,我只想用两个

B
对象初始化 a,但不幸的是,它们需要大量工作来初始化,包括实例化其他对象和使用大量方法。

c++ constructor default-constructor member-initialization
4个回答
6
投票

添加一些静态转换方法怎么样?

class C {
  private:
    static B transform1(D&);
    static B transform2(D&);
  public:
    A a;
    C(D d) :
      a{transform1(d),transform2(d)}
      {}
};

相关:


2
投票

在这种情况下我会使用指针,这是示例的修改版本:

//Class A is not modified
/* a class without a default constructor */
class A {
  public:
    B x1
    B x2
    A(B x1_, B x2_) : x1{x1_}, x2{x2_} {};
};



/* a class that contains an A object and needs to initialize it based on some complex logic */
class C {
  public:
    A* a;   // I declare this as a pointer
    C(D d)
      {
          // Perform all the work and create b1,b2
          a = new A(b1, b2);
      }

    ~C()    // Create a destructor for clean-up
    {
          delete a;
    }

};

使用 new 运算符,我可以随时初始化对象。由于该对象位于类范围内,因此我在析构函数中将其删除(在类范围的末尾)


0
投票

我建议另一个更清晰的解决方案,在类

A
中创建静态方法,并包含所有复杂的构造逻辑。

class A {
public:
   B x1
   B x2
   A(B x1_, B x2_) : x1{x1_}, x2{x2_} {};

   static A FromD(D d) {
       B b1, b2;
       /* Some complex logic filling b1 and b2 */
       return A(b1, b2);
   }
};

class C {
public:
    A a;
    C(D d) :
      a(A::FromD(d))
    {}
};

请注意,此解决方案使用隐式定义的移动构造函数,因此请不要忘记修改您的情况并检查是否需要根据五规则

显式定义它

0
投票

C++ 表达式非常强大,您也许能够使用条件运算符等来解决问题。但是,即使使用这样的工具,您最终也会遇到需要多个语句的限制。 在这种情况下,可以使用 IILE 或简单地使用私有成员函数。

立即调用 lambda 表达式(IILE)

此 C++11 解决方案不需要您定义任何新符号,因此它可以说是最好且最少的方法。然而,由于可读性,有些人可能不喜欢它。

C(D d) : a{
    [&] { /* very complicated */ }(),
    [&] { /* very complicated */ }()
  }
{} // empty constructor body

lambda 表达式可以包含任意数量的复杂逻辑。请注意,末尾的

()
会调用它。

私密会员功能

或者,您可以定义一个包含所有复杂逻辑的(静态)成员函数。

private:
  static B initFirst(D& d);
  static B initSecond(D& d);
public:
  A(D d) : a{initFirst(d), initSecond(d)} {}

也可以调用成员初始化列表中的非静态成员函数,但是,这是非常危险的,因为并非每个子对象都已初始化。 您必须非常小心,不要在该上下文中调用依赖于尚未初始化的成员的成员函数。

© www.soinside.com 2019 - 2024. All rights reserved.