Reputation: 10230
When multiple const properties of a C++ class depend on some intermediate calculation, what is the simplest way to initialize them?
For example, how do I correct the constructor for the class below?
class MyClass {
public:
const int a;
const int b;
MyClass() {
int relatedVariable = rand() % 250;
a = relatedVariable % 100;
b = abs(relatedVariable - 150);
}
};
Upvotes: 14
Views: 7268
Reputation: 15560
This will kinda work for those of us who happen to prefer being less advanced in their coding:
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))
{}
};
The additional member presents an unnecessary overhead — which may or may not be significant for the task at hand. OTOH, the code is simple.
Remember to declare iamStupid
before a
and b
! (see comments)
Upvotes: 3
Reputation: 15560
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()) { }
};
Upvotes: 2
Reputation: 56863
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 ) {}
};
Upvotes: 12
Reputation: 13196
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)) {}
};
Or, you can be lazy, and only store the initial random number, and generate a, b
on demand.
Upvotes: -1
Reputation: 1247
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);
}
};
Upvotes: 1
Reputation: 1823
You could do something like this - not pretty but should do the trick:
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;
Upvotes: 2
Reputation: 476990
Here's a roundabout solution using delegating constructors:
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()) { }
};
Upvotes: 6
Reputation: 35141
Introduce an intermediate class that does the calculation:
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() ) {
}
};
Upvotes: 1