Constructors in C++ Language - c++

Here is the code:
#include<iostream>
using namespace std;
class Rectangle
{
private :
int _width;
int _height;
public :
Rectangle()
: _width{},_height{}
{}
Rectangle(int initial_w, int initial_h)
: _width{initial_w}, _height{initial_h}
{}
int get_width(){return _width;}
};
int main()
{
Rectangle a;
Rectangle(2,3);
cout<<a.get_width()<<endl;
}
I don't understand why it returns 0, i thought it is supposed to be 2.
Please help!!!!!

In your main method, you create a Rectangle a;, which calls your default constructor Rectangle(). Then in the next line you create a temporary element with Rectangle(2,3);, which calls your initialization constructor Rectangle(int initial_w, int initial_h), but it is discarded immediately, as you have not assigned it to a variable. Finally, you output your default-constructed variable a.
It seems what you want to achieve is this:
int main()
{
Rectangle a(2, 3);
cout << a.get_width() << endl;
}

Let's Look at your code within main() line by line:
Rectangle a;
Rectangle(2,3);
cout<<a.get_width()<<endl;
In the first line, you are creating an instance of a Rectangle Object and it is using the default constructor which can in truth be any value as the member variables are not initialized to 0 directly or some other value.
In your second line of code, you are using the classes constructor without declaring it as a variable object while not assigning it to any previously existing variable instance which in turn creates a temporary that will be constructed and destroyed before you even call std::cout.
In your third statement, you are using your class's get_width() message which is returning exactly what the default constructor initialized the member variable to when you declared the variable a.
There are a few ways to fix this:
Rectangle a(2,3);
std::cout << a.get_width() << '\n';
Rectangle b = Rectangle(4,5);
std::cout << b.get_width() << '\n';
The first line uses the user-defined constructor which is preferred in many cases. The second line requires the use of the copy constructor and assignment operator, here it's fairly trivial so, the default versions of these are used. However, in more complex classes and classes that will use the heap and dynamic memory will require the use of the copy constructor and assignment operator to be user-defined.

Related

How to call parameterized constructor of member object variable in a class' default constructor in C++?

I want to initialize member object variables in the default constructor of the class.
Let's consider the following,
class ABC {
ABC(int A, int B) {
a = A;
b = B;
}
int a;
int b;
};
class Foo {
Foo();
ABC m_obj1;
};
From the above example, I would like to initialize "obj1" in "Foo::Foo()".
One of the restrictions I have is that I cannot do so in the initializer list, as I need to do some computation before I could initialize the member. So the option available (ASFAIK) is to do so in the body of the default constructor only.
Any inputs, how could I do this?
Edit: Restricting to C++11
Would this be a correct way,
Foo:Foo() {
int x = 10;
int y = 100;
m_Obj1(x, y); //Is this correct? <--------
}
Depending on your exact problem and requirements, multiple solutions might be available:
Option 1: Use a function to do the computations and call Foo constructor
Foo makeFoo()
{
// Computations here that initialize A and B for obj1 constructor
return Foo(A, B)
}
Option 2: Call a function that does the computations and initialize obj1 in Foo member initializer list
ABC initABC() {
// Some computations
return ABC(A, B)
}
Foo() : obj1(initABC()) {}
Option 3: Dynamically allocate obj1, for instance with a std::unique_ptr
Option 4: Use std::optional or an emulated c++11 version as shown by other answers
You simply call the base constructor inside the initializer list of the derived constructor. The initializer list starts with ":" after the parameters of the constructor. See example code!
There is no problem to call functions inside the initializer list itself.
int CallFunc1(int x) { return x*2; }
int CallFunc2(int y) { return y*4; }
class ABC {
public:
ABC(int A, int B):a{CallFunc1(A)},b{CallFunc2(B)} {
std::cout << "Constructor with " << a << " " << b << " called" << std::endl;
}
private:
int a;
int b;
};
class Foo {
public:
Foo(): obj1(1,2){}
Foo( int a, int b): obj1(a, b){}
private:
ABC obj1;
};
int main()
{
Foo foo;
Foo fooo( 9,10);
}
edit:
The best method I can think of for your case is a copy constructor, being more specific on what you need to store helps a lot since if it is just two ints inside a class dynamic allocation is not worth it, the size of the object being constructed makes a difference to what method is best, copy constructors can be slower with much larger data types as the object has to be created twice: once when it is automatically constructed in the parent objects constructor and again when a temporary object is created and all the values have to be copied, which can be slower then dynamically allocating if the size is larger.
As far as I'm aware all objects in a class are automatically initialized/allocated in the constructor so sadly dynamic memory use may be your best bet here.
If you are fine with having the object initialized but empty so you know it is not 'ready' yet you can later fill it with useful data when you would have wanted to initialize it. This can be done with default constructors that set the things inside the object to null values or something similar so you know the object hasn't been properly initialized yet. Then before using the object you can check whether it has been initialized by checking for the null values or by having put a bool in the object that tells you whether it is initialized. Dynamically allocated would still be better in my opinion and makes the code look cleaner overall as all you need to store is a null pointer until the object is needed and then allocated and set to the pointer. It is also very easy to check if the pointer is equal to nullptr to know the state of your object.
Dynamically allocating memory may be a hassle since you have to make sure to get rid of memory leaks and it is slightly slower than using the stack, but it is a necessary skill for c++ since the stack is not enough when making programs that use more than the few available megabytes of data on the stack so if you are doing this simply to avoid the hassle I recommend learning it properly. It would be nice if you could be more specific about what kind of object you want to do this with or if you just want an answer that works for most cases.
eg:
*ABC obj1 = nullptr;
...object is needed
obj1 = new(ABC(constructor stuff));
...obj1 isn't needed
delete obj1;
or c++ automatically deletes it when the program closes.

Assignment is not giving expected result while assigning different class of objects

In the code snippet below I am assigning a object of type Box into an object of type Circle through the assignment operator, but I am not able to get the expected result.
Current execution result:
circle=6
box=0
Expected result:
circle=6
box=0.7
As per below code snippet, the assignment operator is responsible for initializing the Box object so that it can be assigned to the Circle object. After initialization, the Circle class function getAreaBox (member of Circle class) will call the getAreabox (member of Box class) in order to get the currently set value inside the Circle class constructor. It looks like proper initialization is not happening inside the assignment operator and due to this the expected value is not returned by the getAreabox function.
#include <iostream>
using namespace std;
class Box
{
private:
double area;
public:
Box(double areaval=0.0)
{
area=areaval;
}
double getAreabox() const
{
return area;
}
};
class Circle
{
private:
int area;
Box *box;
public:
Circle(int areaval=0,double boxval=0.0):area(areaval)
{
box= new Box(boxval);
}
const Circle& operator =(const Box& obj)
{
if(&obj!=box)
{
delete box;
box= new Box (obj);
}
return *this;
}
int getAreaCircle()
{
return area;
}
double getAreaBox()
{
double val=box->getAreabox();
return val;
}
~Circle(){delete box;}
};
int main() {
Box box;
Circle circle(6,0.7);
cout<<"circle="<<circle.getAreaCircle()<<endl;
circle=box;
cout<<"box="<<circle.getAreaBox()<<endl;
return 0;
}
Please have a look on my solution in below link for your problem.
http://coliru.stacked-crooked.com/a/1bfb63a8eedeefae
resolution update:
(1) Raw pointer is replaced with smart pointers.
(2) copy assignment operator is replaced with getObject method in order to get the current set Box class object inside constructor.
(3) You needn't to set current value again with box object constructor as it will pick the same value set in Circle class constructor.
(4) No need to have method double getAreaBox() separately in Circle class so code is optimized for the same.
I hope this solution will take care of your need .
Your code does exactly what it is supposed to do. Your expectations are wrong. You expect box = 0.7, but you overwrite box with the statement
circle=box;
The copy constructor destructs the old box inside circle and creates a new one as a copy of 'box'. What value does 'box' have?
Since you default initialise 'box' in your main
Box box;
and the default is 0, the program will print 0 in the last cout statement.
cout << "box=" << circle.getAreaBox() << endl;
will print the value of the box inside the circle ... which has been initialised via copy constructor from the variable 'box'.
If you change the variable 'box' in main to:
int main() {
Box box(0.9);
...
The output will be:
circle=6, box=0.9
P.S. Please don't use pointers (Box*). Just don't. Use std::shared_ptr<> instead. There are ton's of good websites explaining the reasons. Your class 'circle' has a lot of pointer related issues. You can improve your programming skills by reading about
dangling pointer
deep copy vs. shallow copy
std::shared_ptr<> and std::unique_ptr<>
virtual desctructors
Have fun...

What's the difference between these constructors?

I'd like to know what is the difference between these two constructors:
List<type*> list = List<type*>();
and
List<type*> list;
The container List was written by me and has a user-defined constructor which takes no parameters.
In my opinion the first line is correct and the second one looks like Java. However, both compile. So, what is the difference between these two statements?
The first one requires an accessible copy or move constructor while the second one does not.
Consider for example this demontsrative program. If you will not use MS VC++ then the program shall not compile.:)
#include <iostream>
class A
{
public:
A() {}
private:
A( const A& ) { std::cout << "A( const A & )" << std::endl; }
};
int main()
{
A a = A();
}
because the copy constructor is inaccessible even if otherwise the copy operation could be elided.
Also using the first one provides that the corresponding object will be value-initialized while using the second one provides that the corresponding object will be default initialized.

std::vector initialization of class member

I have read that std::vector always initializes it's objects with their default values say for an int it is 0. The same should be applicable even for classes where the default constructor is called. However the results shown by a test program are a bit different :-
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
int i;
A(){};
};
class B
{
public:
int i;
B() = default;
};
template <typename T>
void seev (const vector<T> &v)
{
for (auto &x:v)
{
cout << x.i << ' ';
}
cout << '\n';
}
int main()
{
vector<int> vi(5); // just to show that std::vector always default initializes values & hence int will be 0 here
vector<A> va(5);
vector<B> vb(5);
for (auto x: vi)
cout << x << ' ';
cout << '\n';
seev (va);
seev (vb);
return 0;
}
The output is :-
0 0 0 0 0
8854016 0 8847696 0 8854016
0 0 0 0 0
My question is why was the value of member i undefined for A & not for B ? What difference did the constructor signatures :-
A() {}
&
B() = default;
make ?
There is a difference between default initialization and value initialization. The difference is shown for B but not for A:
When a class has a non-= defaulted constructor, this constructor is called when either default or value initialization is used. Its responsibility is to initialize all members appropriately.
When a class either has no constructor or an = defaulted default constructor the initialization of the members depends on how the object is constructed: when initializing the object without parenthesis default initialization is done which leaves subobjects without a default constructor uninitialized. When initializing the object with parenthesis value initialization is done which value initializes all subobjects. Value initialization of built-in types mean they get a suitable zero value while default initialization of built-in types means they are left uninitialized.
Since A has an explicitly written default constructor, its constructor needs to initialize all members which aren't of class type with a default constructor. B has an implicitly written default constructor and default or value initialization is performed as necessary for the subobjects.
The objects in a std::vector<T> are constructed using T() (if no other arguments are provides as is the case, e.g., for push_back() or emplace_back()). For A members that means they are left uninitialized, for B members that means they are zero initialized.
When creating a vector with a specific size, the vector doesn't set default values, it uses something called value initialization which is something completely different.
For primitive types, like e.g. int, that means the value will be zero-initialized (i.e. zero). But for objects with constructors the default constructor (if it has one) will be used.
In the case of your A class, the default constructor does not initialize the i member variable, so it will be uninitialized and have an indeterminate value, by printing that value you have undefined behavior.
As for the B class it's a POD type which means that value initialization of the whole object will also value-initialize all members. B is a POD type because it has a trivial default constructor (which A does not have).
A() {};
You are not initializing A::i in A() so its value is unspecified after value initialization. This behaviour is different to what you would get with a compiler-provided default constructor.
A() = default;
Defining as default on the other hand has the effect of providing a constructor with the same semantics of the compiler-synthesized default constructor. That is to say, A::i would get value-initialized (and therefore zero-initialized) when an A object is value initialized with expressions such as A() or A{}.
Note: this can be fixed by either dropping the definition of the default constructor, define it as default, or explicitly initialize i.
struct A
{
// Compiler provided A() will initialize i
// when A is value initialized
int i;
};
or, equivalently in terms of initialization semantics,
struct A
{
int i;
A() = default; // useful if other constructors defined
};
An "empty" constructor will not initialize anything, so the fact that va contains zero is just luck/coincidence. The default constructor will do nothing either, so they will produce the same thing. What you are seeing is undefined behaviour (or unspecified behaviour perhaps - as we shouldn't really expect world war three to break out because of an uninitialized variable).
The problem is that std::vector is supposed to call the default constructor & not set the values by default. The default constructor of int sets it's value to 0 hence you get a std::vector<int> with all values initialized with 0. However you default constructor of A is empty & hence it doesn't initialize i with any value. If you define the constructor as :-
A() { i = 0; }
Then your vector would definitely initialize the i of the objects of A with 0. What default does is this :-
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A()
{
cout << "Default constructed A\n";
}
A (A &obj)
{
cout << "Copy constructed A\n";
}
};
class X
{
int x;
double d;
bool b;
A obj;
public:
X() = default;
void show()
{
cout << fixed << x << ' ' << d << ' ' << b << '\n';
}
};
int main()
{
cout << boolalpha;
vector<X> v(1);
v[0].show();
return 0;
}
/* Output :-
Default constructed A
0 0.000000 false
*/
What B() = default; roughly means as far I get from this test code that it is a replacement for :-
B()
{
i = 0;
d = 0.00;
b = false;
// obj is default initialized
}
ie the initialization of the data members with their default values (for primitives) or default constructors (for classes). But this is only for runtime initialization which means for locally created objects the definition is same as B() = {}.
So the thing was that class A had a user defined constructor (with an empty body) & hence didn't initialize because that's how the programmer defined it. On the other hand class B had a constructor that was left on to the compiler to call implicitly. Hence for local objects it didn't do any specific initialization but for dynamic objects (like that of a std::vector) it did the value type initialization.

Compiler-generated copy/assignment functions for classes with reference and const members

The book I'm reading says that when your class contains a member that's a reference or a const, using the compiler-generated copy constructor or assignment operators won't work. For instance,
#include <iostream>
#include <string>
using namespace std;
class TextBlock
{
public:
TextBlock (string str) : s(str) {
cout << "Constructor is being called" << endl;
}
string& s;
};
int main () {
TextBlock p("foo");
TextBlock q(p);
q = p;
cout << "Q's s is " << q.s << endl;
return(0);
}
According to my book, both the lines TextBlock q(p); and q = p; should return compiler errors. But using the g++ compiler for Linux, I'm only getting an error for the line q = p; When I comment that out, this works fine and the code compiles. The correct s is output for Q, so it's apparently being copied by the compiler-generated copy constructor. I get the same results when I change the line string& s; to const string s.
Have there been some changes to C++ that now allow the copy constructor to be generated automatically for reference and const objects, but not the assignment operator? Or maybe I'm just not understanding the book correctly? Any thoughts?
The book is wrong. A const member or a reference member will
inhibit generation of the default copy assignment operator, but
doesn't prevent the compiler from generating a copy constructor.
Don't try to learn a special rule here.
The compiler-generated default versions of special member functions follow a simple pattern:
The type-appropriate special member function is called for every subobject (base classes and members).
From that, you can work out every case.
int i;
int &ri1 = i;
int &ri2 = ri1;
is allowed, so copying an object containing an int& is allowed.
There is no assignment operator for references (ri2 = ri1; does not rebind the reference), so assignment is not allowed.
References can't be default constructed:
int& ri; // error
so a type containing int& can't be default-constructed.
An important consideration is that the access checks are done for compiler-defaulted code just as if you had written it yourself. So interesting things can happen if a base class has, for example, a private copy constructor... and you don't have to learn special rules for any of them.