在构造函数中初始化多个相关const属性的最简单方法

Simplest way to initialize multiple related const properties in a constructor?

本文关键字:属性 const 最简单 方法 构造函数 初始化      更新时间:2023-10-16

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

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

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

在c++ 11中,您可以简单地使用委托构造函数:

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

这里有一个使用委托构造函数的迂回解决方案:

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()) { }
};

对于我们这些碰巧喜欢在编码中不那么高级的人来说,这将有点工作:

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

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

记住在 ab之前声明iamStupid !(见注释)

您可以这样做——不漂亮,但应该可以达到目的:

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;

如果您使用的是不支持委托构造函数的旧编译器,这里有适用于旧语言版本的相同方法:

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()) { }
};

引入一个中间类来进行计算:

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() ) {
    }
};

Const是类的用户和实现者之间的契约。它表明类用户不应该修改成员变量,从而提供不可变的对象设计。构造函数可以初始化该状态。也就是说,最好将它们隐藏在私有访问限定符之后,并提供允许只读的访问器。暂时删除const-ness的正确方法是使用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);
}

};

您可以将ab设置为私有,并提供从类外部访问它们的值的getter。

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

或者,您可以使用子对象初始化器并以某种方式缓存随机数。打开优化甚至可以删除生成的程序文本中的临时变量。

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

请记住,子对象的构造是按照类中成员声明的顺序进行的,并且忽略初始化列表中子对象的顺序。

或者,您可以偷懒,只存储初始随机数,并根据需要生成a, b