5

我有一个带有const成员的类,一个构造函数调用另一个填充了额外值的构造函数。通常我可以为此使用冒号初始化程序,但该函数很复杂(printf/ sprintf-like)并且需要我在堆栈上使用一个变量,所以我必须在构造函数的主体中执行此操作并使用分配*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

4 回答 4

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 ...
};
于 2012-08-19T23:27:00.907 回答
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)) { }
};
于 2012-08-20T00:46:33.383 回答
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朋友。

于 2012-08-20T00:47:03.767 回答
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);

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

于 2012-08-19T23:46:10.267 回答