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 {}
Related
STRUGGLING WITH C++ CONSTRUCTOR ARGUMENTS
So, I've just came from TS/JS/Py and trying to understand C++ concepts. But I'm struggling with using the parameter of constructor of the class FOR declaring default value for an argument. Here is the code I'm trying to run:
double Phythagorean_Hypotenuse (int& a, int& b ) {
return sqrt((a * a) + (b * b));
};
class Triangle {
public:
int a;
int b;
double c;
Triangle(int a_param, int b_param, double c_param = Phythagorean_Hypotenuse(a_param, b_param)) {
a = a_param;
b = b_param;
c = c_param;
}
};
and inside of the main function
Triangle mytri_1(10, 20);
std::cout << mytri_1.a << std:endl;
But when I try to run this code, IDE is throwing me some errors like
[Error] 'a_param' was not declared in this scope
or
[Error] call to 'Triangle::Triangle(int, int, double)' uses the default argument for parameter 3, which is not yet defined
So, please, can someone who can fix this answer the question?
Thanks.
There are some issues that prevent your code from compiling, namely:
Constructors do not have return type.
double c_param = Phythagorean_Hypotenuse(a_param, b_param) is not valid for a parameter, a_param, b_param will not be recognized.
Recommend change:
Since the result of a hypothenuse calculation will most likely be a decimal value, c should be a double.
You can do something like this:
Running sample
#include <iostream>
#include <cmath>
double Phythagorean_Hypotenuse (int& a, int& b ) {
return sqrt((a * a) + (b * b));
};
class Triangle {
public:
int a;
int b;
double c; //should be double
//initializer list is a good practice for member initialization
Triangle(int a_param, int b_param)
: a(a_param), b(b_param), c(Phythagorean_Hypotenuse(a, b)) {}
};
int main(){
Triangle mytri_1(10, 20);
std::cout << mytri_1.a << std::endl;
std::cout << mytri_1.b << std::endl;
std::cout << mytri_1.c << std::endl;
}
Output:
10
20
22.3607
As the compiler is pointing out, the other constructor arguments are not available as default parameters for the c_param argument. Rather than using default values, just overload the constructor, including one that just accepts 2 parameters. This constructor can then invoke the other constructor that accepts all 3:
// Constructor overload that accepts all 3 parameters
Triangle(int a_param, int b_param, double c_param):
a(a_param), b(b_param), c(c_param) {
}
// Constructor overload that accepts just a and b, call the other constructor
// to set all 3 members
Triangle(int a_param, int b_param):
Triangle(a_param, b_param, Phythagorean_Hypotenuse(a_param, b_param)) {
}
Default parameter values cannot reference other parameters. You can define two overloads, one of which delegates to the other, to do what you want:
class Triangle {
public:
double a;
double b;
double c;
Triangle(double a_param, double b_param, double c_param)
: a{a_param},
b{b_param},
c{c_param}
{}
Triangle(double a_param, double b_param)
: Triangle{a_param, b_param, Phythagorean_Hypotenuse(a_param, b_param)}
{}
};
Live Demo
A few other notes:
Class constructors do not have a return type. I changed void Triangle(...) to Triangle(...)
I used constructor initialization lists instead of assignment in the constructor's body. There's likely no difference for small primitive values like ints or doubles, but it's a good habit to get into and can make a big difference for more complex types
int doesn't make sense for the type of c (or a or b for that matter). The sides of a triangle are unlikely to all be integers
There's no reason to pass parameters to Pythagorean_Hypotenuse by reference. It's simpler and likely faster to pass them by value
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.
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.
}
How should I write a constructor for a class to initialize a member that is a const structure / has const fields?
In the following example, I define a constructor within structure B and it works fine to initialize it's const fields.
But when I try to use the same technique to initialize const fields of structure C within class A it doesn't work. Can someone please help me and rewrite my class A in a way, that it starts working?
#include <iostream>
class A
{
public:
struct C
{
C (const int _x) : x (_x) {}
const int x;
};
C c (3);
};
int main (int argc, char *argv[])
{
struct B
{
B (const int _x) : x (_x) {}
const int x;
};
B b (2);
std::cout << b.x << std::endl;
A a;
std::cout << a.c.x << std::endl;
return 0;
}
P.S.
I did some search and I think, I understand, that unless I have C++11 support or want to use boost library, I have to define a helper function to initialize a const struct within initialization list
(C++ Constant structure member initialization)
but it seems to be crazy that I have to define alike struct, but with non const fields to initialize a struct with const fields, doesn't it?
Another thing that I found tells that I should initialize const members in a constructor of the class A, rather than in a constructor of the struct C (C++ compile time error: expected identifier before numeric constant) but it also seems crazy to me, because why should I rewrite a class constructor every time I want to add a new struct, isn't it more convenient to have a separate constructor for each struct C within the class A?
I would be grateful to any comments that could possibly clarify my confusion.
I'd do the job like this:
#include <iostream>
class A {
public:
struct C {
C(const int _x) : x(_x) {}
const int x;
};
C c; // (3);
A() : c(3) {}
};
int main(int argc, char *argv []) {
A a;
std::cout << a.c.x << std::endl;
return 0;
}
Note that it's not a matter of using a ctor in A or in C, but of the ctor for A telling how the ctor for C should be invoked. If the value that will be passed will always be 3 that's not necessary, but I'm assuming you want to be a able to pass a value of your choice when you create the C object, and it will remain constant after that.
If the value will always be the same (3 in this case) you can simplify things a lot by also making the constant static:
struct A {
struct C {
static const int x = 3;
};
C c;
};
int main() {
A a;
std::cout << a.c.x << "\n";
}
So, if the value is identical for all instances of that class, make it static const, initialize it in place, and life is good. If the value is not known until you create an instance of the object, and remains constant thereafter for the life of that object, you need to pass it in through the constructors.
For a slightly different case, there's a third possibility: if C is an independent class (not nested inside of A) you might have a situation where other instances of C use various values, but all instances of C inside an A always use the same value. In this case, you'd do something like:
struct C {
const int x;
C(int x) : x(x) {}
};
struct A {
C c;
A() : c(3) {}
};
Of course, you can do the same thing when C is nested inside of A, but when/if you do, it generally means you're setting the same value for all instances of C, so you might as well use the static const approach instead. The obvious exception would be if A had multiple constructors, so (for example) A's default constructor passed one value for C::x and its copy constructor passed a different value.
I know that default constructors initialize objects to their default values, but how do we view these values? If there's a variable of type int, it is supposed to be initialized to 0. But how do we actually view these default values of the constructors? Can anyone please provide a code snippet to demonstrate the same?
Unless specified otherwise, objects are constructed with their default constructor, only if one is available.
And for example ints are not initialized.
This is a common source of huge troubles and bugs, because it can have any value.
So the rule is , always initialise your variables, and for a class you do it in the initialization list
class A
{
private:
int i;
float f;
char * pC;
MyObjectType myObject;
public:
A() : // the initialisation list is after the :
i(0),
f(2.5),
pC(NULL),
myObject("parameter_for_special_constructor")
{}
}
}
In C++, int is not a class and does not have a default (or any other) constructor.
An int is not guaranteed to be initialised to 0.
If you have a class that has an int as an attribute, you should explicitly initialise it in each of the class's constructors (not just the default one).
class sample
{
private:
int x;
public:
sample()
:x(0)
{
}
sample(const int n)
:x(n)
{
}
sample(const sample& other)
:x(other.x)
{
}
// [...]
};
This way you (and users of your class) can "view" the default values.
Good coding practice: write your own constructor, so you know how it will be initialized. This is portable and guaranteed to always have the same behaviour. Your code will be easier to read and the compiler knows how to make that efficient, especially when using the special notation:
class Foo
{
public:
Foo() : i(0), j(0) {}
private:
int i;
int j;
};
AFAIK, if T is a type (not necessarily a class), T() returns a default value for the type T. Here's a small test I ran:
int main()
{
char c = char();
int i = int();
cout << "c = " << hex << (int) c << endl;
cout << "i = " << i << endl;
}
The output is:
c = 0
i = 0
Default constructors do not automatically initialise ints to 0. You can use parentheses to indicate the default value though.
struct X
{
int x;
};
struct X x1; // x1.x is not necessarily 0
struct Y
{
int y;
Y() : y()
{
}
};
struct Y y1; // y1.y will be 0
show your code
And if your int value is a member of class .
you must give it a value in your default constructor func
The default constructor is which can be invoked with 0 parameters. For example
struct X
{
X(int x = 3) //default constructor
{
//...
}
};
It initializes the object to whichever state you code it to initialize. However, if you don't define any constructor at all the compiler will attempt to generate a default constructor for you - which, in turn is equivalent to a constructor with no arguments and no body. That means that all the members of class/struct type will be initialized with their def. ctors and all the members of primitive types like int will remain uninitialized. Please note that I specialy noted that the compiler will attempt to generate a dflt ctor, because it can fail to do so, for example when one or more members of the class do not have default constructors. HTH
AS soon as you have created an object start printing the values such as ob.x.
Thats the only way u can know what default constructor has assigned to the variables.