Delegate Constructor C++

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 Shapes 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



Leave a reply



Submit