在使用const成员构造对象时调用另一个构造函数

时间:2012-08-19 23:22:33

标签: c++ constructor const

我有一个带有const成员的类,还有一个构造函数调用另一个构造函数,并且填充了额外的值。通常我可以使用冒号初始值设定项,但函数很复杂(printf / sprintf - 喜欢)并且要求我在堆栈上使用变量,所以我必须在构造函数的主体中执行此操作并使用assign *this到新对象。但当然这是无效的,因为我的成员变量是const

class A
{
public:
    A(int b) : b(b), c(0), d(0) // required because const
    {
        int newC = 0;
        int newD = 0;
        myfunc(b, &newC, &newD);
        *this = A(b, newC, newD); // invalid because members are const

        // "cannot define the implicit default assignment operator for 'A', because non-static const member 'b' can't use default assignment operator"
        // or, sometimes,
        // "error: overload resolution selected implicitly-deleted copy assignment operator"
    };
    A(int b, int c, int d) : b(b), c(c), d(d) { };

    const int b;
    const int c;
    const int d;
};

A a(0);

(我没有明确删除赋值运算符。)我声明成员const因为我希望它们是公共的,但不是可变的。

是否有一些规范的方法来解决这个问题,而不使用可怕的演员和强制覆盖成员' const岬?什么是最好的解决方案?

4 个答案:

答案 0 :(得分:2)

如何制作辅助功能:

class A
{
    static int initializor(int b) { int n; myfunc(b, &n); return n; }
public:
    explicit A(int b_) : b(b_), c(initializor(b_)) { }
    A(int b_, int c_)  : b(b_), c(c_)              { }

    // ... as before ...
};

答案 1 :(得分:2)

您可以添加参数类并使用C ++ 11构造函数委派或基类:

struct parameters {
    int b; int c; int d;
    parameters(int b): b(b), c(), d() {
        myfunc(b, &c, &d);
    }
};

// constructor delegation
class A {
public:
    A(int b): A(parameters(b)) { }
    A(parameters p): b(p.b), c(p.c), d(p.d) { }
};

// base/wrapper
class ABase {
    ABase(parameters p): b(p.b), c(p.c), d(p.d) { }
};

class A: public ABase {
public:
    A(int b): ABase(parameters(b)) { }
};

答案 2 :(得分:1)

我更喜欢Kerrek SB's answer,但在您的情况下,您可能无法为每个成员轻松制作单独的初始化函数。

在这种情况下,另一种解决方案是将成员移动到基类,并使用具有非const成员的帮助程序类初始化该基类。您的初始化代码将移动到辅助类的构造函数,并且可以毫无问题地进行分配。

class A_init
{
  public:
    A_init(int b)
    {
      // do whatever you like with c and d:
      c = ...;
      d = ...;
    }

    int c; // Note: non-const
    int d; // Note: non-const
};

class A_base
{
   public:
     A_base(int b, A_init init) : b(b), c(init.c), d(init.d) {}
     A_base(int b, int c, int d) : b(b), c(c), d(d) {}

     const int b;
     const int c;
     const int d;
};

class A : public A_base
{
  public:
    A(int b) : A_base(b, A_init(b)) {}
    A(int b, int c, int d) : A_base(b, c, d) {}
};

如果想要限制对A_init的访问权限,可以切换为私有,并声明A朋友。

答案 3 :(得分:0)

在哪里放置myfunc的结果,以便可以从不同的mem-initializers设置和使用它?在默认参数中怎么样?

class A
{
private:
    struct InitData;
public:
    A(int b, InitData data=InitData());
    A(int b, int c, int d) : b(b), c(c), d(d) { };

    const int b;
    const int c;
    const int d;
};

struct A::InitData
{
    int setup(int b);
    int c;
    int d;
};

inline int A::InitData::setup(int b)
{
    myfunc(b, &c, &d);
    return b;
}

inline A::A(int b_, InitData data)
    : b(data.setup(b_)),
      c(data.c),
      d(data.d)  {}

A a(0);

由于组合类型是私密的并且没有转换,因此不小心使用它或滥用它的风险很小。