13

当 C++ 类的多个 const 属性依赖于一些中间计算时,初始化它们的最简单方法是什么?

例如,如何更正下面类的构造函数?

class MyClass {
public:
    const int a;
    const int b;

    MyClass() {
        int relatedVariable = rand() % 250;
        a = relatedVariable % 100;
        b = abs(relatedVariable - 150);
    }
};
4

8 回答 8

11

With C++11, you can simply use a delegating constructor:

class MyClass
{
public:
    const int a;
    const int b;

private:
    MyClass( int relatedVariable )
      : a( relatedVariable % 100 ),
        b( abs( relatedVariable - 150 ) ) {}

public:
    MyClass() : MyClass( rand() % 250 ) {}
};
于 2013-03-20T22:46:21.593 回答
6

这是使用委托构造函数的迂回解决方案:

class MyClass
{
    MyClass(int aa, int bb) : a(aa), b(bb) { }

    static MyClass Maker() { int x = /* ... */; return MyClass(x * 2, x * 3); }

    int const a;
    int const b;

public:
    MyClass(MyClass const &) = default;
    MyClass() : MyClass(Maker()) { }
};
于 2013-03-20T22:23:23.163 回答
3

这对于我们这些碰巧喜欢在编码方面不太先进的人来说有点用:

class MyClass {
public:

    int iamStupid;      /* K.I.S.S. */

    const int a;
    const int b;

    MyClass()
      : iamStupid(rand() % 250)
      , a(iamStupid % 150)
      , b(abs(iamStupid - 150))
    {}
};

额外的成员会带来不必要的开销——这对于手头的任务可能很重要,也可能不重要。OTOH,代码很简单。

记得在andiamStupid 之前 声明!(看评论)ab

于 2013-03-20T22:19:01.700 回答
2

你可以做这样的事情 - 不漂亮,但应该做的伎俩:

class MyClass {
public:
    const int a;
    const int b;
    static int relatedVariable;
    MyClass() :
        a(setRand()),
        b(relatedVariable)  {}
    static const int setRand()
    {
        relatedVariable = rand() % 250;
        return relatedVariable;
    }
};
int MyClass::relatedVariable = 0;
于 2013-03-20T22:15:49.517 回答
2

In case if you are stuck with an ancient compiler which doesn't support delegating constructors, here's the same approach adapted for the older language version:

class MyClassBase {
public:
    const int a;
    const int b;
    MyClassBase(int a, int b) : a(a), b(b) {}
};

class MyClass : public MyClassBase {
    static MyClassBase Maker() {
        int x = rand() % 250;
        return MyClassBase(x % 100, abs(x - 150));
    }
public:
    using MyClassBase::a;
    using MyClassBase::b;

    MyClass() : MyClassBase(Maker()) { }
};
于 2013-03-20T22:48:50.030 回答
1

引入一个执行计算的中间类:

class ConstCalc {

   public:
    ConstCalc(int related) : rv(related){}

    int a() const { return rv % 100; } 
    int b() const { return abs( rv - 150 ) ; } 

   private:
    const int rv;
};

class MyClass {
public:
    const int a;
    const int b;

    MyClass( const ConstCalc c ) : a( c.a() ), b( c.b() ) {
    }
};
于 2013-03-20T22:13:16.237 回答
1

Const is a contract between a class's user and implementor. It indicates that the class user should not modify the member variables, thus providing an immutable object design. It is fine for a constructor to otherwise initialize that state. That said, it might be better to hide these behind a private access qualifier and to provide accessors that allow read-only. The correct way to temporarily remove const-ness is using the const_cast<>.

class MyClass {
public:
   const int a;
   const int b;

MyClass() : a(0), b(0) {
    int relatedVariable = rand() % 250;
    const_cast<int&>(a) = relatedVariable % 100;
    const_cast<int&>(b) = abs(relatedVariable - 150);
}

};

于 2013-03-20T22:26:32.303 回答
-1

You could make a and b private, and provide getters to access their values from outside the class.

class MyClass
{
private:
    int a, b; // private
public:
    int getA() { return a; }
    int getB() { return b; }

    MyClass()
    {
        int relatedVariable = rand() % 250;
        a = relatedVariable % 100;
        b = abs(relatedVariable - 150);
    }
};

Or, you could just use subobject initializers and cache the random number somehow. Turning the optimization on might even remove the temporary variable in the generated program text.

class MyClass
{
private:
    int temp; // this is a workaround
public:
    const int a;
    const int b;

    MyClass() : temp(rand() % 250), a(temp % 100), b(abs(temp - 150)) {}
};

Remember that subobject construction happens in the order that members are declared in the class, and that the order of subobjects in the initialization list is ignored.

Or, you can be lazy, and only store the initial random number, and generate a, b on demand.

于 2013-03-20T22:26:55.607 回答