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.
Related
Similar questions have been answered but I still cannot find a solution to my problem. I am indeed not able to call the constructor of class Point inside class Rectangle. After having read some answers, I would approximately do it like this, but it does not work:
class Point {
public:
Point(int x, int y);
private:
int x;
int y;
};
Point::Point(int xx, int yy) {
x = xx;
y = yy;
}
class Rectangle {
public:
Rectangle(Point a, Point b) : Point(int x, int y); // this is wrong
private:
Point a;
Point b;
};
Rectangle::Rectangle(Point aa, Point bb) : Point(int x, int y) { // same as above
?
}
Can anyone help me to understand how to implement and fix this code (I know that declaring Rectangle as a struct makes it way easier)?
It is not clear what you expected this line to do:
Rectangle(Point a, Point b) : Point(int x, int y);
The place to initialize members is not the constructors body. And the correct syntax for the member initiazer list is:
Rectangle(Point a, Point b) : a(a), b(b) {}
Note that the initializer list is a place where shadowing is not an issue, you can use the same name for parameter and member, because there is no ambiguity. a(a) initializes the member a with parameter a.
Note that also constructor of Point should be:
Point::Point(int xx, int yy) : x(xx),y(yy) {
}
For int members it won't make a huge difference, but for class types it does make a huge difference: Members are initialzed before the body of the constructor runs. Fist initializing and then assigning in the constructor is inefficient and sometimes just wrong. On the other hand, there is no reason to not use the initializer list when the members are ints.
PS
(I know that declaring Rectangle as a struct makes it way easier)?
I think you refer to members being public in the struct. However, struct and class are just two different keywords to declare a class. The only difference is default access (see here for details: When should you use a class vs a struct in C++?) and those two definitions are identical:
class foo {
int a;
public:
int b;
};
struct foo {
private:
int a;
public:
int b;
};
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
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));
I have some C++ code that produces an error:
class foo{
public:
int a;
int b;
};
foo test;
test.a=1; //error here
test.b=2;
int main()
{
//some code operating on object test
}
I get this error:
error: expected constructor, destructor, or type conversion before '.' token
What does the error mean and how do I fix it?
It's called a constructor. Include one that takes the wanted values as arguments.
Like
class foo
{
public:
foo(int aa, int bb)
: a(aa), b(bb) // Initializer list, set the member variables
{}
private:
int a, b;
};
foo test(1, 2);
As noted by chris, you can also use aggregate initialization if the fields are public, like in your example:
foo test = { 1, 2 };
This also works in C++11 compatible compilers with the constructor as in my example.
This should be:
class foo
{
public:
int a;
int b;
};
foo test;
int main()
{
test.a=1;
test.b=2;
}
You can not write code outside of a method/function, you can only declare variables/classes/types, etc.
You need a default constructor:
//add this
foo(): a(0), b(0) { };
//maybe a deconstructor, depending on your compiler
~foo() { };
You cannot call the variable initialization outside a function. As mentioned in a comment
test.a=1
test.b=2
is thus invalid. If you really need an initialization, use a constructor like
class foo
{
public:
foo(const int a, const int b);
int a;
int b;
}
Otherwise you could put the initialization e.g. into the main function.
When I try to create an object of class A having only parametrized Constructor in class B, I get following errors:
A ob(5); error: expected identifier before numeric constant
A ob(x); error: x is not a type
class A {
public:
int z;
A(int y){z = y;}
};
class B {
public:
int x;
A ob(5); or A ob(x);//This line is creating a problem
};
I searched for the same and got that we can solve this problem by writing
A ob;
B():ob(5);
OR
int x;
A ob;
B():ob(x); //here x will be uninitialized though
But I am thinking why it was giving error in the prior case. Can someone explain in detail. Thanks.
You cannot assign default value to class member in C++. You need to define constructor.
class A {
public:
int z;
A(int y){z = y;}
};
class B {
public:
int x;
A ob; //
B() : x(5), ob(x) {}
};