构造具有const成员的对象时调用另一个构造函数

Calling another constructor when constructing an object with const members

本文关键字:对象 调用 另一个 构造函数 成员 const      更新时间:2023-10-16

我有一个包含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?这里的最佳解决方案是什么?

您可以添加一个参数类,并使用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)) { }
};

制作一个辅助函数怎么样:

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

我更喜欢Kerrek SB的答案,但在您的情况下,复杂的是您无法轻松为每个成员创建单独的初始化函数。

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

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的访问,可以切换到private并声明A为朋友。

myfunc的结果放在哪里,以便可以从不同的mem初始化器设置和使用它?在默认参数中如何?

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

由于编好的类型是私有的,没有转换,因此意外使用或滥用它的风险很小。