Delegating constructors and reference parameters
Assuming your members of 'A' are references, one way to allow this would be to have some special "null" value for each of your classes:
class B {};
class C {};
class A
{
public:
A();
A(const B& b);
A(const B& b, const C& c);
private:
const B& b_;
const C& c_;
static const B null_b;
static const C null_c;
};
A::A() : A(null_b, null_c) {}
A::A(const B& b) : A(b, null_c) {}
A::A(const B& b, const C& c) : b_(b), c_(c) {
}
How do I delegate this constructor?
Here's a slightly refactored version of your code that reflects more modern C++ practice (since 2011):
struct Point {
Point() = default;
Point(double i, double j) : x(i), y(j) {}
double x = 0;
double y = 0;
};
struct Triangle {
Triangle() = default;
Triangle(Point i, Point j, Point k) : a(i), b(j), c(k) {}
Point a, b, c;
};
This does use the "constructor delegation" feature you mentioned because that applies to constructors calling other constructors of the same class. It uses initialization lists and class member initializers (= 0
) to make the code more concise and idiomatic (by being able to use the = default
declarations for the default constructors, rather than having to write them ourselves).
If you really wanted to use constructor delegation for Point
, you'd write the default constructor like this instead:
Point() : Point(0, 0) {}
And then you wouldn't need the = 0
for x
and y
.
Delegate Constructor C++
You need to do the second. Delegating constructors only works in the constructor's initialization list, otherwise you'll just create a temporary or do other mistakes like you mentioned.
Why did C++11 introduce delegating constructors?
Delegating constructors prevent code duplication (and all the possible errors and flaws that come with it : increased maintenance, decreased readability...), which is a good thing.
It is also the only way to delegate the initialization list (for members and bases initializations), i.e. you really can't replace this feature by having a shared Init()
method for your constructors.
Examples:
1) Common initialization from N1986 proposal :
class X {
X( int, W& );
Y y_;
Z z_;
public:
X();
X( int );
X( W& );
};
X::X( int i, W& e ) : y_(i), z_(e) { /*Common Init*/ }
X::X() : X( 42, 3.14 ) { SomePostInitialization(); }
X::X( int i ) : X( i, 3.14 ) { OtherPostInitialization(); }
X::X( W& w ) : X( 53, w ) { /* no post-init */ }
2) Delegation with both constructor and copy constructor, also from N1986 proposal :
class FullName {
string firstName_;
string middleName_;
string lastName_;
public:
FullName(string firstName, string middleName, string lastName);
FullName(string firstName, string lastName);
FullName(const FullName& name);
};
FullName::FullName(string firstName, string middleName, string lastName)
: firstName_(firstName), middleName_(middleName), lastName_(lastName)
{
// ...
}
// delegating copy constructor
FullName::FullName(const FullName& name)
: FullName(name.firstName_, name.middleName_, name.lastName_)
{
// ...
}
// delegating constructor
FullName::FullName(string firstName, string lastName)
: FullName(firstName, "", lastName)
{
// ...
}
3) MSDN gives this example, with constructors performing argument validation (as commented, this design is debatable) :
class class_c {
public:
int max;
int min;
int middle;
class_c() {}
class_c(int my_max) {
max = my_max > 0 ? my_max : 10;
}
class_c(int my_max, int my_min) {
max = my_max > 0 ? my_max : 10;
min = my_min > 0 && my_min < max ? my_min : 1;
}
class_c(int my_max, int my_min, int my_middle) {
max = my_max > 0 ? my_max : 10;
min = my_min > 0 && my_min < max ? my_min : 1;
middle = my_middle < max && my_middle > min ? my_middle : 5;
}
};
Thanks to constructors delegation, it reduces to :
class class_c {
public:
int max;
int min;
int middle;
class_c(int my_max) {
max = my_max > 0 ? my_max : 10;
}
class_c(int my_max, int my_min) : class_c(my_max) {
min = my_min > 0 && my_min < max ? my_min : 1;
}
class_c(int my_max, int my_min, int my_middle) : class_c (my_max, my_min){
middle = my_middle < max && my_middle > min ? my_middle : 5;
}
};
Links:
- Delegating Constructors (r3) Proposal - N1986
- Stroustrup C++ FAQ : Delegating constructors
C++ Delegated Constructor
If it is relevant, I am using VS2012.
It is, because Visual Studio doesn't implement this C++11 feature. Sorry. There are quite a lot of C++11 features they don't implement.
Member initialization while using delegate constructor
You are not using a delegating constructor.
A delegating constructor calls another constructor in the same class.
For example, in:
struct Foo
{
Foo(int) : Foo("delegate") {} // #1
Foo(std::string) {} // #2
};
#1 and #2 are both constructors for Foo
, and constructor #1 delegates to constructor #2.
In your case, you have a class that is derived from another class, and in:
Circle::Circle(std::string name) : Shape::Shape(), name(name)
You are initializing the base Shape
portion of the Circle
object, by calling Shape
s default constructor. You then move on after that to finish initializing the rest of the members of the Circle
class. This is not a delegating constructor.
Delegating constructors in c++ () or {}
()
uses value initialization if the parentheses are empty, or direct initialization if non-empty.
{}
uses list initialization, which implies value initialization if the braces are empty, or aggregate initialization if the initialized object is an aggregate.
Since your X
is a simple int
, there's no difference between initializing it with ()
or {}
.
Related Topics
How to Declare a Templated Struct/Class as a Friend
How to Return a Std::String.C_Str()
How to Generate a Calling Graph For C++ Code
Initializing a Two Dimensional Std::Vector
How to Emulate Template≪Auto X≫
Overload Resolution Failure When Streaming Object Via Implicit Conversion to String
A Most Vexing Parse Error: Constructor With No Arguments
Msvc++ Variadic Macro Expansion
Winmain and Main() in C++ (Extended)
C++11 Allows In-Class Initialization of Non-Static and Non-Const Members. What Changed
What Is a Simple Example of Floating Point/Rounding Error
How to Get Double Quotes into a String Literal
Exporting Classes Containing 'Std::' Objects (Vector, Map etc.) from a Dll
How to Print an Unsigned Char as Hex in C++ Using Ostream