C++ initialized unnamed struct member in constructor - c++

example:
class A
{
public:
A();
private:
struct {int x, y; } position_;
};
my question is: how to init position_.x and position_.y before the constructor function body? like:
A::A() //init position_.x and position_.y here
{
}

Just use a normal constructor initializer list:
A::A()
: position_{0, 0}
{
}

You can initialize it like any data member1: in the constructor initialization list:
A() : position_{1,2} {}
at the point of declaration:
struct {int x, y;} position_{1, 2};
or both.
1 Assuming you have C++11 or higher

Related

Initialize first entries of an array of objects in class constructor initialization list

If I have class A that declares Class B and instantiates an array of it.
class A{
class B{
int x, y;
};
B arrB[10];
public:
A();
};
Then, my issue is that I would like to initialize the first two objects of "arrB" in Class A using initialization list:
A::A(): arrB[0](1, 2), arrB[1](3, 4) {}
But the compiler does not accept it.
Can I initialize specific objects of the array or not? If yes, how to do it?
Thanks
The problem is that B hides its members by default as private because it is a class. Declare B a struct, or expose int x, y as public to be able to use aggregate initialization:
class A{
class B{
public:
int x, y;
};
B arrB[10] = {{1,2}};
public:
A();
};
The second problem is that you're not using aggregate initialization properly.
A::A(): arrB[0](1, 2), arrB[1](3, 4) {}
Should be
A::A(): arrB{{1, 2}, {3, 4}} {}
Demo
In order to initialize an array in the class member initialization list you need to use curly braces like you would if you were initializing an array in a function.
Thus if you wanted to initialize the first and second element of the array you would need to use at least
A() : arrB{{1,2}, {3,4}} {}
as the first set ({1,2}) says make arrB[0] a B with x and y initialized to 1 and 2 respectively. The second set ({3,4}) says make arrB[1] a B with x and y initialized to 3 and 4 respectively.
You do have to do one thing though in order to make this work. You either need to make B and aggregate by making x and y public, or you can provide a constructor for B that takes to values. Doing that lets you have either
class A{
class B{
public:
int x, y;
};
B arrB[10];
public:
A() : arrB{{}, {3,4}} {}
};
int main() {
A a;
}
or
class A{
class B{
int x, y;
public:
B() : x(), y() {} // need this so default instances are value initialized (zeroed in this case)
B(int x, int y) : x(x), y(y) {}
};
B arrB[10];
public:
A() : arrB{{}, {3,4}} {}
};
int main() {
A a;
}

Why no other constructor is being allowed?

I am learning about initializer list and learnt that const members must be initialized using it, because you cannot initialize it using default constructor or parameterised constructor.
class Foo
{
private:
const int y;
public:
Foo(int yy) :y(yy){}
int getY();
};
Now suppose if I have another member int x; not a const,Why can't I initialize it using default constructor, What is the idea behind this restriction?
The code that gives error:
class Foo
{
private:
const int y;
int x;
public:
Foo(int yy) :y(yy){}
Foo()
{
x = 100;
}
int getY();
};
I am learning about initializer list and learnt that const members must be initialized using it, because you cannot initialize it using default constructor or parameterised constructor.
Const members can be initialized in the member initializer list of both a default constructor and any parametrised constructor. (A default constructor is a constructor that can be invoked without parameters.)
Now suppose if I have another member int x; not a const,Why can't I initialize it using default constructor, What is the idea behind this restriction?
You can initialize any number of members (there is probably some implementation defined limit, but it's not relevant to this question) in the default constructor. There is no such restriction that you describe.
Demo, class with two members, both initialized in the default constructor:
struct Foo {
const int y;
int x;
Foo(): y(1), x(100){}
};
Edit for the mcve.
The code that gives error:
class Foo
{
private:
const int y;
int x;
public:
Foo(int yy) :y(yy){}
Foo()
{
x = 100;
}
int getY();
};
All constructors must initialize const members. Your parametrised constructor does initialize y, but the default constructor doesn't. That is why it doesn't work. See my demo above for a working example.
PS. Your parametrised constructor doesn't initialize x, but that is OK: x isn't const, so you can assign a value to it later.
In my code if I have a parameterised constructor like Foo(int xx) { x = xx;}
It will not give any error
This program:
struct Foo {
const int y;
int x;
Foo(int xx) { x = xx;}
};
Is ill formed in standard C++. If your compiler accepts it without a warning, then it isn't standard compliant.
Unclear what you're trying to accomplish.
Following code simply compiles
class Foo
{
private:
int _nonConst;
const int _const;
public:
Foo() : _const(10), _nonConst(11)
{
}
Foo(int x) : _const(x), _nonConst(x)
{
}
};
I am not sure I understood the question properly. To summarize what you can and can't do:
// .h
class MyClass
{
private:
int x;
const int y;
public:
MyClass();
MyClass(int initValue);
};
// .cpp
// The following is legal
MyClass::MyClass()
: x(0), y(0)
{}
// Alternatively, the following is legal too.
MyClass::MyClass()
: y(0)
{
x = 0;
}
// This is not legal: y cannot be initialized that way as it is const.
// No problem for x though.
MyClass::MyClass()
{
x = 0;
y = 0; // You cannot do that
}
// The following is legal
MyClass::MyClass(int initValue)
: x(initValue), y(initValue)
{}
// Alternatively, the following is legal too.
MyClass::MyClass(int initValue)
: y(initValue)
{
x = initValue;
}
// This is not legal: y cannot be initialized that way as it is const.
// No problem for x though.
MyClass::MyClass(int initValue)
{
x = initValue;
y = initValue; // You cannot do that
}
Of course, you can only have one CTor per declared signature. The examples above are 3 alternatives - 2 legal and 1 illegal - per declared signature.

How can we initialize a parametrized constructor as default for a string?

For an integer we can do it as
class A{
int a;
public:
A(int x = 0){ a = x; }
};
It is difficult to understand exactly what you are asking. I think you are asking how to specify a default value for a std::string parameter. If that is the case, you can do it like this:
class A{
string a;
public:
A(string x = ""){ a = x; }
};
or:
class A{
string a;
public:
A(const string &x = string()){ a = x; }
};
Though, in either case, you should be initializing the a member using the constructor's member initialization list instead of the constructor's body:
class A{
string a;
public:
A(string x = "") : a(x) { }
};
class A{
string a;
public:
A(const string &x = string()) : a(x) { }
};

re-initialise using delegating constructor

I have this class X, using delegating constructor I want to change only the value i and j as 0. Is it possible to do so?
class X{
public:
X() = default;
X(int ival, int jval) : i{ ival }, j{ jval } {}
X(int new_i) : i{ new_i }, X(i, 0) {} //error here
private:
int i;
int j;
};
int main()
{
X x{ 345, 54 };
x = X{ 34 }; //annoymous copy changes only the i:member
return 0;
}
EDIT: I know X(int new_int) : X{new_int, 0} will work but i wanted to know what's the error if initialise one more variable in the list.
May be I have another z and I want to initialise that along with i and j.
i.e. X(int new_i) :z{ new_i }, X(new_i, 0) {}
Just use
X(int new_i) : X(new_i, 0) {}
From the C++ Draft Standard N3337 (emphasis mine):
12.6.2 Initializing bases and members
6 A mem-initializer-list can delegate to another constructor of the constructor’s class using any class-or-decltype that denotes the constructor’s class itself. If a mem-initializer-id designates the constructor’s class,
it shall be the only mem-initializer;
Why don't you do this?
X(int new_i) :X(new_i, 0){...}
In this way, you will set j-th value to 0, and have only x variable.
You cannot have a delegating constructor and another member-initialiser in the initialiser list. That's not allowed, because the order of initialisation cannot possibly be the order of member declaration, instead some variables will be initialised twice, which is potentially ill-defined.
If your example were allowed, then the constructor in question would first initialise i<-new_i, then i<--i, then j<--0. With non-const int, this may be feasable, but not with more general types.
Simply initialise the objects via the delegation:
class X
{
public:
X() = default;
X(int ival, int jval) : i{ival}, j{jval} {}
X(int ival) : X(ival, 0) {}
private:
int i;
int j;
};
Though in this case, it's better to use default arguments:
class X
{
public:
X() = default;
X(int ival, int jval=0) : i{ival}, j{jval} {}
private:
int i;
int j;
};
You should also consider to use the explicit keyword for single-argument constructors to avoid unpleasant surprises ... as in
void foo(X);
foo(1); // calls foo(X(1));

Inheriting constructors in C++0x

Lets say I have the following code in what we expect to become the next C++ standard:
int f(int x)
{
std::cout << x;
return x * x;
}
struct A
{
A(int x) : m_x(x) {}
int m_x;
};
struct B : A
{
using A::A;
B() : m_y(f(m_x)) {}
int m_y;
};
int main()
{
B(5);
}
Would this call the default constructor of B and print out 5 and set m_y = 25? Or will the default constructor of B not run, and leave m_y uninitialized?
And if the latter, what is the rationale behind not calling the B default constructor? It is quite clear that the A(int) B inherits only initialises A, and leaves B in an indeterminate state. Why would C++ choose undefined behaviour over simply calling the default constructor of B()? It largely defeats the purpose of the inheriting constructors feature.
Edit:
Perhaps this should be allowed:
using A::A : m_y(...) { std::cout << "constructing..." << std::endl; ...; }
using A::A; implicitly declares B(int) in the derived class. That is it.
The rest of your program should not work as you expect. Because you're invoking B(int) with B(5), and that leaves m_y uninitialized.
See this example from Bjarne Stroustrup's site:
struct B1 {
B1(int) { }
};
struct D1 : B1 {
using B1::B1; // implicitly declares D1(int)
int x;
};
void test()
{
D1 d(6); // Oops: d.x is not initialized
D1 e; // error: D1 has no default constructor
}
http://www2.research.att.com/~bs/C++0xFAQ.html#inheriting
Another example from the same link:
struct D1 : B1 {
using B1::B1; // implicitly declares D1(int)
int x{0}; // note: x is initialized
};
void test()
{
D1 d(6); // d.x is zero
}