I have a class A
with lots of data members, some of which are constant. All data members have proper copy constructors, so I want to default a copy constructor of my class:
class A
{
public:
A() : a(1) {}
A(const A& op) = default;
private:
// ... Lots of constant and non-constant member data ...
const int a;
};
Then, I want to write a constructor which accepts a reference to A
and a value which should initialize one of constant data members:
A(const A& op, const int a_);
Here op
should be copied, and a
should be initialized with a_
after that or instead of copying. I would like to avoid manual initialization of all data members by delegating to a copy constructor, but how to overwrite my const data member in this case?
For example:
// Illegal: constructor delegation can't be mixed with field initialization.
A(const A& op, const int a_) : A(op), a(a_) {}
// Illegal: attempt to assign constant member.
A(const A& op, const int a_) : A(op) { a = a_; }
// Hack. May lead to UB in some cases.
A(const A& op, const int a_) : A(op)
{
*(const_cast<int*>(&a)) = a_;
// ... or same tricks with memcpy ...
}
Obviously, all of these approaches are evil as they try to initialize a
twice.
Another solution is to move all constant data to a base class and write all needed ctors, but it looks to verbose.
Is there a cleaner way to implement A(const A&, int a_)
?
Delegating constructors. Constructors are allowed to call other constructors from the same class. This process is called delegating constructors (or constructor chaining). To have one constructor call another, simply call the constructor in the member initializer list.
A constructor can initialize an object that has been declared as const , volatile or const volatile .
To initialize the const value using constructor, we have to use the initialize list. This initializer list is used to initialize the data member of a class. The list of members, that will be initialized, will be present after the constructor after colon. members will be separated using comma.
When a variable is declared as const it means that , variable is read-only ,and cant be changed . so in order to make a variable read only it should be initialized at the time it is declared.
Unfortunately, C++ const field initialization is a very special case with specific syntax, so is constructor delegation, and the constructor syntax has no provision to mix them, so there can be no clean and neat solution here (at least for current C++ versions, maybe later...). The best I can imagine is:
class A
{
public:
A() : a(1) {}
A(const A& op):
const_field1(op.const_field1),..., a(op.a) // all const fields here
{ init() };
A(const A& op, int a_):
const_field1(op.const_field1),..., a(a)) // dup line at editor level
private:
void init(void) {
// init non const fields here
}
// ... Lots of constant and non-constant member data ...
const int a;
};
It does not make sense if you have only the copy ctor and one single additional one, but it could ease code maintenability if you have many additional ctors. It is a pity that only non const field setting can be factorized across different ctors with a private method, but C++ standard is like that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With