【问题标题】:How to initialize multiple constant member variables that shares complex initialization code?如何初始化共享复杂初始化代码的多个常量成员变量?
【发布时间】:2019-03-27 16:50:22
【问题描述】:

简介

我们来介绍这个简单的例子:

#include <cmath>

class X
{
public: // Members

    /// A ^ B + A
    int A;

    /// A ^ B + B
    int B;

public: // Specials

    X(
        const int & A,
        const int & B
    )
        : A(A)
        , B(B)
    {
        const auto Pow = static_cast<int>(std::pow(A, B));

        this->A += Pow;
        this->B += Pow;
    }
};

琐事

  • 引入的类有两个成员变量:AB
  • 它们的值分别为A ^ B + AA ^ B + B
  • 它们都共享共同的复杂初始化代码(假设std::pow 是复杂的)。

问题

我想让AB 都成为const 成员。

问题

如何在不重复复杂初始化的情况下做到这一点(避免两次调用std::pow)?

我尝试过的

#include <cmath>

class X
{
public: // Members

    /// A ^ B + A
    const int A;

    /// A ^ B + B
    const int B;

public: // Helpers

    struct Init
    {
    public: // Members

        int A;
        int B;

    public: // Specials

        Init(
            const int & A,
            const int & B
        )
            : A(A)
            , B(B)
        {
            const auto Pow = static_cast<int>(std::pow(A, B));

            this->A += Pow;
            this->B += Pow;
        }
    };

public: // Specials

    X(
        const Init& Init
    )
        : A(Init.A)
        , B(Init.B)
    {};

    X(
        const int & A,
        const int & B
    )
        : X(Init(
            A,
            B
        ))
    {};
};
  1. 创建struct Init,该struct Init扮演类X的过去版本的角色。
  2. 使X 成为const 成员,同时保持Init 成员非const
  3. 使用构造函数委托将构造函数参数重定向到Init
  4. 将非const 成员变量从Init 移动到X 并使其成为const

但是,我的解决方案似乎过于复杂。任何帮助将不胜感激。

没有目标

  • 创建另一个X 成员变量来存储公共代码结果(ie std::pow)。
  • X 类之外添加另一个间接级别(例如X 引入基类)。

注意

解决方案可以使用比 C++11 更新的 C++ 版本。

【问题讨论】:

  • 您是否考虑过将成员设为私有、非 const 并且只设为访问器?这是启用此类功能的正常方式。
  • 我想使用const,因为我将存储这些值直到程序退出(eg 好几个小时),而不是因为我不希望它们被编辑/visible,所以 getters/setters 不是我的目标。
  • 变量的持续时间将是类实例的持续时间,无论它们是const 还是非const。你在想static吗?
  • 另外,您是否考虑过您可能没有启用 C++11?当我将 Init init(1,2); X x(init); std::cout &lt;&lt; x.A &lt;&lt; " " &lt;&lt; x.B &lt;&lt; std::endl; 放在我的 main 中时,你的代码对我来说很好,输出是 2 3
  • 我的代码中会有很多这个类的实例,所以static不是一个选项。我的代码中有std::latest,它现在使用了许多 C++17 和一个 C++20 功能,所以我确实启用了 C++11。顺便说一句,我的问题已经解决了,谢谢。

标签: c++ constructor constants member-initialization


【解决方案1】:

在这种情况下,使用delegating constructor 是一个不错的选择。

class X
{
   public: // Members

      /// A ^ B + A
      const int A;

      /// A ^ B + B
      const int B;

   public:

      X(int a, int b) : X(a, b, func1(a, b)) {}

   private:

      X(int a, int b, int c) : A(func2(a, b, c)), B(func3(a, b, c)) {}

      static int func1(int a, int b) { return std::pow(a,b); }
      static int func2(int a, int b, int c) { return (a + c); }
      static int func3(int a, int b, int c) { return (b + c); }
};

func1func2func3 中的逻辑/计算可以根据需要简单或复杂。

【讨论】:

  • 这正是我错过的,谢谢 :) 理由:虽然 NathanOliver 的回答也解决了问题,但它增加了使用不同名称来初始化类的要求(ie @987654326 @ 而不仅仅是X)。我已将您的答案标记为解决方案,因为它没有添加此类要求。
【解决方案2】:

您可以使用工厂函数来解决这个问题。您将X 的构造函数设为私有,然后使用友元/静态函数获取X 的对象。然后你可以在函数体中编写复杂的代码,然后将这些值传递给 X 的构造函数。这看起来像

class X
{
public:
    const int A;
    const int B;
    friend X make_X(int a, int b)
    {
        // do complex stuff
        return X(complex_result1, complex_result2);
    }
    // or
    static X make(int a, int b)
    {
        // do complex stuff
        return X(complex_result1, complex_result2);
    }
private:
    X(const int  A, const int  B) : A(A), B(B) {}
};

并且会像这样使用

X foo = make_x(a, b);
//or
X foo = X::make(a, b);

【讨论】:

  • 我觉得使用委托构造函数比使用友元函数更简洁?
  • 也可以设为静态成员make(int, int),写成X::make(a,b)而不是make_X(a,b)
  • @chtz 是的。我已经添加了。谢谢。
  • @Borgleader 我觉得你是对的。我越看 R Sahu 的回答越喜欢它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 2012-08-23
  • 2014-09-08
  • 2020-09-20
  • 1970-01-01
相关资源
最近更新 更多