Constructor initializing the data member [duplicate] - c++

This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 3 years ago.
I am new to c++ programing.This is an example in Bjarne Stroustrup's c++ book.
Can any one explain to me what this line does
X(int i =0) :m{i} { } //a constructor ( initialize the data member m )
Can anyone tell me what does this ':' symbol does.I am new to c++ programs.
class X {
private: //the representation (implementation) is private
int m;
public: //the user interface is public
X(int i =0) :m{i} { } //a constructor ( initialize the data memberm )
int mf(int i) //a member function
{
int old = m;
m = i; // set new value
return old; // return the old value
}
};
X var {7}; // a variable of type X initialized to 7
int user(X var, X∗ ptr) {
int x = var.mf(7); // access using . (dot)
int y = ptr−>mf(9); // access using -> (arrow)
int z = var.m; //error : cannot access private member
}

Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. 
#include<iostream>
using namespace std;
class Point {
    int x;
    int y;
public:
    Point(int i = 0, int j = 0) : x(i), y(j) {} 
    /*  The above use of Initializer list is optional as the 
        constructor can also be written as:
        Point(int i = 0, int j = 0) {
            x = i;
            y = j;
        }
    */    
    int getX() const {return x;}
    int getY() const {return y;}
};
int main() {
  Point t1(10, 15);
  cout << "x = " << t1.getX() << ", ";
  cout << "y = " << t1.getY();
  return 0;
}
/* OUTPUT:
   x = 10, y = 15
*/
The above code is just an example for syntax of the Initializer list. In the above code, x and y can also be easily initialed inside the constructor. But there are situations where initialization of data members inside constructor doesn’t work and Initializer List must be used. Following are such cases:
1) For initialization of non-static const data members:
const data members must be initialized using Initializer List. In the following example, “t” is a const data member of Test class and is initialized using Initializer List. Reason for initializing the const data member in initializer list is because no memory is allocated separately for const data member, it is folded in the symbol table due to which we need to initialize it in the initializer list.
Also, it is a copy constructor and we don’t need to call the assignment operator which means we are avoiding one extra operation.

Related

Undefined behaviour of Designated initializers in C++

The following C++20 program is accepted without any warning in all compiles I have tried:
struct A { const int & x = z; int y = x; int z; };
int main()
{
return A{.z=3}.y;
}
https://gcc.godbolt.org/z/nqb95zb7c
But every program returns some arbitrary value. Is it right to assume that this is undefined behavior?
Members are initialized in the order they appear in the class definition, hence the designated initializer is not that relevant, and also this
struct A {
const int & x = z;
int y = x; // <- read of indeterminate value !
int z = 42; // <- doesn't really matter because y is initialized before !
};
int main() {
return A{}.y;
}
is undefined for the same reason.
See also the example from cppreference:
struct A {
string str;
int n = 42;
int m = -1;
};
A{.m=21} // Initializes str with {}, which calls the default constructor
// then initializes n with = 42
// then initializes m with = 21
The example is actually to illustrate something else, but it also shows how members are initialized in order.

Initializing a reference member: reason for different syntax

I have two classes, with one on them having an object of the other as reference Member:
class myClass{
public:
myClass() { };
};
class mySecondClass {
public:
mySecondClass(myClass& reference)
{
myClassReference = reference; //doesn't get accepted by the compiler
};
myClass& myObjectReference;
};
I found out (thanks to Passing by reference to a constructor
), that mySecondClass(myClass& reference) : myObjectReference(reference){}; does the job.
But why can't I use myObjectReference = reference;?
It's because { myClassReference = reference; } is considered as an
assignment to something which is supposed to be already initialised.
The member initialisation list : member1{value1}, member2{value2}...
is intended to provide the initial value (nothing is supposed to
be valid before).
For the specific case of a reference, it's the same situation as
int i=4;
int &r=i; // the reference is initialised (alias for i)
r=5; // the reference itself is not changed but
// the referenced object (i) is assigned
In the constructor
mySecondClass(myClass& reference)
{
myClassReference = reference; //doesn't get accepted by the compiler
};
there is used reference myClassReference that shall be initialized when it is created. However the variable was not initialized. There is used the copy assignment operator.
In this constructor
mySecondClass(myClass& reference) : myObjectReference(reference){}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
the reference is created and initialized in the mem-initializer list.
To make it more clear consider the following demonstrative program.
#include <iostream>
struct Int
{
Int() { std::cout << "Int()\n"; }
Int( int x ) : x( x ) { std::cout << "Int( " << x << " )\n"; }
Int & operator =( int x )
{
std::cout << "Int & operator =( " << x << " )\n";
this->x = x;
return *this;
}
int x;
};
struct A
{
A( int x )
{
this->value = x;
}
Int value;
};
struct B
{
B( int x ) : value( x ) {}
Int value;
};
int main()
{
A a( 10 );
std::cout << '\n';
B b( 10 );
return 0;
}
Its output is
Int()
Int & operator =( 10 )
Int( 10 )
That is when the body of the constructor A gets the control the data member was already created using the default constructor of the class Int. Within the body of the constructor there is used the assignment operator.
Opposite to the constructor of the class A the constructor of the class B created the data member in the mem-inkitializer list using the constructor of the class Int with a parameter.
So now imagine that you are using a reference in the class A. Then it is "default-initialized" that is it is not actually initialized by any valid object to which it shell refer. So in the body of the constructor you are trying to assign a value to an invalid reference that refers nowhere. So the compiler issues an error.

The colon symbol after constructor parameter list [duplicate]

This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 4 years ago.
class Sales_data {
public:
Sales_data(int i, int j, int k) : x(i), y(j), z(k) {
}
private:
int x,y,z;
};
In the above code(more specifically in Sales_data constructor(recited below)), I don't understand the use of colon and comma separated list.
Sales_data(int i, int j, int k) : x(i), y(j), z(k) {
}
I have never seen a colon(":") following any function/constructor parameter list. What does this colon mean/signify here ?
Moreover, what is this comma separated list after colon ?
You may be confused, because the member variable name (x) is same as the function parameter (also x), which you can always avoid for clarity. Simplified code can look like so.
add_x(int x1) : x(x1) // a contructor that initializes the member vaiable x to x1
{
}
Still confused? then you can go for this ( not so optimize though)
add_x(int x1)
{
x = x1;
}
This is a constructor
This is not a standard function/method. Each class (struct) can have constructor(s). The constructor has the same name as the class and can optionally take parameters.
struct add_x {
int x;
add_x(int x) : x(x) {} // This is a constructor with one paramter
};
To make it easier to read let us format it better.
struct add_x {
int x;
add_x(int x) // Constructor that takes one argument.
: x(x) // This is called the initializer list.
{} // This is the body of the constructor.
};
The initializer list allows you to list out the member variables (comma separated) and initialize them before the body of the constructor is executed.
In this case the member x is initialized with the parameter x.
#include <iostream>
int main()
{
add_x test(5);
std::cout << test.x << "\n"; // Should print 5
// Note in my example I have removed the private
// section so I can read the value x.
}

Instance variable initialization in C++ private area

In class A,counter b(5); doesn't work.
while counter a; (the call of the default constructor) works.
Why? Is it not possible to call a parameterized constructor for an instance variable?
class counter {
private:
int value;
public:
counter() { this->value = 0; }
counter(int value) { this->value = value; }
};
class A {
private:
// works
counter a;
// works (since C++11)
int x = 5;
// doesn't work
counter b(5);
};
int main()
{
// works
counter myCounter;
// works as well
counter mySecondCounter(5);
return 0;
}
If allowed, counter b(5); technically declares a function named b that returns a counter object by value, and takes a single argument that's an integer.
While that, very likely, would not be the intention of the coder, that's why it is not allowed.
In Bjarne's words about this rule for In-Class Initializers:
We can specify an initializer for a non-static data member in the class declaration. For example:
class A {
public:
int a {7};
int b = 77;
};
For pretty obscure technical reasons related to parsing and name lookup, the {} and = initializer
notations can be used for in-class member initializers, but the () notation cannot.
It is possible. Change
counter b(5);
to
counter b = counter(5);
It is perhaps more elegant to initialise in a constructor intialisation list.
class A {
private:
A() : b(5) {}
counter a;
int x = 5;
counter b;
};
You have four options:
class A {
private:
counter C1{5};
// Works, only with single parameter constructors
counter C2 = 5;
// Works, with any number of parameters
counter C3 = counter(5);
counter C4;
// Constructor initializer list, works with any number of parameters
A() : C4(5) {}
};
In C++, this is not the correct syntax for initializing members with default values.
There are two options to solve it:
1.use operator =
counter b = counter(5);
2.use constructor with initialization list
A() : a(),b(5) {}

C++: Classes & Constructors: Using Initialization Lists to Initialize Fields

Full code. Line specified later.
#include <iostream>
#include <string>
using namespace std;
class X
{
private:
int i;
float f;
char c;
public:
X(int first=1, float second=2.0, char third='a') : i(first) , f(second) , c(third) { }
void print() { cout << i << " " << f << " " << c << endl;}
};
int main()
{
X var1;
var1.print();
return 0;
}
What exactly is going on on this line:
X(int first=1, float second=2.0, char third='a') : i(first) , f(second) , c(third) { }
As far as I can understand (could be wrong), we are declaring objects first, second, and third of type (class) X. We are initializing them during declaration. What's going on after the colon? What's going on altogether?
What exactly is going on on this line:
X(int first=1, float second=2.0, char third='a')
: i(first) , f(second) , c(third) {
}
It's a constructor which takes 3 parameters with default values.
This part : i(first) , f(second) , c(third) is called a member initializer list.The member initializer list consists
of a comma-separated list of initializers preceded by a colon. It’s placed after the closing
parenthesis of the argument list and before the opening bracket of the function body.
Only constructors can use this initializer-list syntax. const class members must be initialized in member initializers.
The stuff in the parenthesis are default values for the arguments to the constructor, and the stuff after the colon initializes those items after the colon.
The colon notation is most commonly used to invoke the constructors of other objects the class uses.
You have class X with three fields: i, f, c.
You have defined a constructor with three default parameters - when this constructor invoked fields are initialized with parameters (passed to constructor or defaults).
It's like:
X (int first=1, float second=2.0, char third='a')
{
i = first;
f = second;
c = third;
}
Your line is just an another way to initialize fields, usually they are equal (there are some differences with inheritance).
In your main code you're creating a local variable var1 of type X, so the constructor is called. You don't pass any parameters, so default values are used.
As result, you have one local object of type X initialized with default values listed in constructor.
X(int first=1, float second=2.0, char third='a') : i(first) , f(second) , c(third) { }
This is a constructor for X. There are three agruments, each having a default value so that it can be invoked in different ways
X myX;
X myX(first);
X myX(first, second);
X myX(first, second, third);
The section after the arguments
: i(first) , f(second) , c(third)
are initializers for the i, f and c members. If possible this style of initialization is preferred over initialization in the function body, and if the members are constant types, this style is required.
Then there is an empty body for the constructor {}