Per my understanding, I know that when an object is instantiated, a constructor is called once. But I can't understand why both constructors are called and only one object is instantiated
#include <iostream>
using namespace std;
#define print(me) cout << me << endl;
class A
{
public:
A() { print("default called"); }
A(int x) { print("paramterized called"); }
};
int main()
{
A a;
a = A(10);
return 0;
}
I got output:
default called
parameterized called
In these lines
A a;
a = A(10);
there are created two objects of the type A. The first one is created in the declaration using the default constructor
A a;
And the second one is a temporary object created in the expression A( 10 )
a = A(10);
that then is assigned using the copy assignment operator to the already existent object a.
Due to the copy elision you could avoid the use of the default constructor by writing initially
A a = A( 10 );
In fact due to the copy elision it is equivalent to
A a( 10 );
provided that the copy constructor is not declared as explicit.
You are also calling function while creating it with A a;
You can solve it by initializing value while creating it like this:
int main()
{
A a = A(10);
}
Or as a Fareanor said :
int main()
{
A a(10);
}
Related
C code
#include <stdio.h>
typedef struct
{
int a;
}A;
int main()
{
A(); // this line gives error
return 0;
}
Output
Error: Expected identifier or '('
C++ code
#include <iostream>
struct A
{
int a;
A()
{
std::cout<<"Ctor-A\n";
}
~A()
{
std::cout<<"Dctor-A\n";
}
};
int main()
{
A(); // creates temporary object and destroyed it
return 0;
}
Output
Ctor-A
Dctor-A
I know about the "Rule of three", but code becomes complicated and most compilers don't give errors if we don't follow the rule. So I avoided creation of a copy constructor and an overloaded assignment operator.
Why does A()/A{} create a temporary object in C++, but not in C? What's another way to create a temporary object in C?
In C (C99 and later) you can create a structure with automatic lifetime using a Compound Literal.
The syntax is (A){ initializers, for, struct, members }.
The lifetime is automatic, not temporary, so the structure created in this way does not vanish at the end of the full-expression, but at the end of the enclosing scope.
This expression
A()
is considered by C compilers as a function call. In C++ such an expression means a call of a constructor provided that A is a class type.
To create a temporary object in C you could declare a function like for example
struct A { int a; } A( int x )
{
struct A a = { .a = x };
return a;
}
and then you can call the function creating a temporary object of the type struct A like
A( 10 );
Here is a demonstrative program.
#include <stdio.h>
struct A { int a; } A( int x )
{
struct A a = { .a = x };
return a;
}
int main(void)
{
struct A a = A( 10 );
printf( "a.a = %d\n", a.a );
return 0;
}
The program output is
a.a = 10
A() calls the constructor for the struct A in the C++ code. However, C doesn't support constructors / destructors, or even objects (in the sense of OOP) in fact. The only way to create a temporary object as you describe in C would be to declare a variable of type A and wait for it to go out of scope, where the memory allocated for it will be popped from the stack, or to allocate a variable on the heap and free it in the next line.
I have this code:
i receive next error: A::A(int) candidate expect 1 argument, 0 provided but I cannot understand what the problem is.
#include <iostream>
using namespace std;
class A
{
int x;
public:
A(int i):x(i) {}
int get_x() const {return x;}
};
class B:public A
{
int *y;
public:
B(int i):A(i) {y=new int[i]; for(int j=0;j<i;j++) y[j]=1;}
B(B&);
int &operator[] (int i) {return y[i];}
};
B::B(B&a)
{
y=new int[a.get_x()];
for(int i=0;i<a.get_x();i++) y[i]=a[i];
}
ostream& operator<<(ostream& o, B a)
{
for(int i=0;i<a.get_x();i++) o<<a[i];
return o;
}
int main()
{
B b(5);
cout<<b;
return 0;
}
Because A does not have a constructor that takes 0 arguments you need to explicitly call the constructor with arguments provided from any class constructor that inherits from A, which is B in this case.
In your first constructor:
B(int i):A(i) {y=new int[i]; for(int j=0;j<i;j++) y[j]=1;}
You are doing this well by calling A(i).
But in your second constructor:
B::B(B&a)
{
y=new int[a.get_x()];
for(int i=0;i<a.get_x();i++) y[i]=a[i];
}
There is no call to A's constructor and thus you get an error since the compiler doesn't know how to create an A object, you probably meant to do :
B::B(B&a) : A(a.get_x())
{
y=new int[a.get_x()];
for(int i=0;i<a.get_x();i++) y[i]=a[i];
}
Your second B constructor B::B(B&a) implicitly tries to construct the base class A using its default constructor, which is not defined.
You may explicitly call the A(int) constructor, i.e.:
B::B(B&a)
: A(a.get_x())
{
...
The problem is that when you declare an object of type B you also sort need to construct an instance of A.
In B::B(B&a) you do not explicitly call any constructor for A, so the compiler try to call the one with no parameters A::A(), but it fails since it is not declared.
You have to either declare a A::A() in A or explicitly call one of the available constructors in A from B's constructror.
Note that A::A() could be automatically generated by the compiler, and is called default constructor. Read more about it here
Question:
Is there a difference between the following initializations?
(A) What exactly is the second one doing?
(B) Is one more efficient than the other?
int variable = 0;
int variable = int();
This question also applies to other data types such as std::string:
std::string variable = "";
std::string variable = std::string();
Background:
I basically got the idea here (the second code sample for the accepted answer) when I was trying to empty out a stringstream.
I also had to start using it when I began learning classes and realized that member variable initializations had to be done in the constructor, not just following its definition in the header. For example, initializing a vector:
// Header.h
class myClass
{
private:
std::vector<std::string> myVector;
};
// Source.cpp
myClass::myClass()
{
for (int i=0;i<5;i++)
{
myVector.push_back(std::string());
}
}
Any clarity on this will be greatly appreciated!
Edit
After reading again, I realized that you explicitely asked about the default constructor while I provided a lot of examples with a 1 parameter constructor.
For Visual Studio C++ compiler, the following code only executes the default constructor, but if the copy constructor is defined explicit, it still complains because the never called copy constructor can't be called this way.
#include <iostream>
class MyInt {
public:
MyInt() : _i(0) {
std::cout << "default" << std::endl;
}
MyInt(const MyInt& other) : _i(other._i) {
std::cout << "copy" << std::endl;
}
int _i;
};
int main() {
MyInt i = MyInt();
return i._i;
}
Original (typo fixed)
For int variables, there is no difference between the forms.
Custom classes with a 1 argument constructor also accept assignment initialization, unless the constructor is marked as explicit, then the constructor call Type varname(argument) is required and assignment produces a compiler error.
See below examples for the different variants
class MyInt1 {
public:
MyInt1(int i) : _i(i) { }
int _i;
};
class MyInt2 {
public:
explicit MyInt2(int i) : _i(i) { }
int _i;
};
class MyInt3 {
public:
explicit MyInt3(int i) : _i(i) { }
explicit MyInt3(const MyInt3& other) : _i(other._i) { }
int _i;
};
int main() {
MyInt1 i1_1(0); // int constructor called
MyInt1 i1_2 = 0; // int constructor called
MyInt2 i2_1(0); // int constructor called
MyInt2 i2_2 = 0; // int constructor explicit - ERROR!
MyInt2 i2_3 = MyInt2(0); // int constructor called
MyInt3 i3_1(0); // int constructor called
MyInt3 i3_2 = 0; // int constructor explicit - ERROR!
MyInt3 i3_3 = MyInt3(0); // int constructor called, copy constructor explicit - ERROR!
}
The main difference between something like:
int i = int(); and int i = 0;
is that using a default constructor such as int() or string(), etc., unless overloaded/overridden, will set the variable equal to NULL, while just about all other forms of instantiation and declarations of variables will require some form of value assignment and therefore will not be NULL but a specific value.
As far as my knowledge on efficiency, neither one is "better".
I am a newbie to c++ and just learning by reading a book.
So the question may be a bit stupid.
Here is my program:
#include <iostream>
using namespace std;
class Fish
{
public:
virtual Fish* Clone() = 0;
};
class Tuna : public Fish
{
public:
Tuna(const Tuna& SourceTuna)
{
cout << "Copy Constructor of Tuna invoked" << endl;
}
Tuna* Clone()
{
return new Tuna(*this);
}
};
I have question on
return new Tuna(*this);
First, why does the copy constructor return a pointer of Tuna?
Usually, invoking the copy constructor will return a copied instance directly.
For example:
class Student
{
public:
Student(){}
Student(const Student& Input) { cout << "Copy Ctor Invoked\n"; }
};
int main()
{
Student a;
Student b(a);
return 0;
}
Base on my understanding, what Student b(a); does is copying an instance of a and named b.
So why does new Tuna(*this) is not returning an instance instead of a pointer?
Second, why is point of this,ie. *this , provided in the argument?
Base on my understanding this is a pointer to the current object, which mean *this is a pointer to the pointer of the current object. I try to use int to simulate the situation.
// The input argument is the same as a copy constructor
int SimulateCopyConstructor(const int& Input){ return 0; }
void main()
{
int a = 10; // a simulate an object
int* b = &a; // b is a pointer of object a, which simulate "this"
int** c = &b; // c is a pointer to pointer of object a, which simulate of "*this"
SimulateCopyConstructor(a); // It can compile
SimulateCopyConstructor(b); // cannot compile
SimulateCopyConstructor(c); // cannot compile
}
I think sending (*this) to copy constructor is similar to the situation c above. But it does not compile. So how does it works?
Student b(a);
Does not return a Student object. It declares it and instructs compiler to call a copy contructor on the new object allocated on stack.
new Student(a);
This indeed returns a pointer to a new Student object because operator new does. And (a) there instructs the compiler to call a copy contructor on that object that was allocated by new.
However if you had a function doing this:
Student foo(){ return Student(a); }
That would create a new Student object on stack, call copy constructor and then return the resulting object from the function.
Why does the following not work when chaining constructors:
#include <iostream>
#include <vector>
class cls {
public:
cls() {cls(5);} // want to resize v to 5
cls(int n) {v.resize(n);}
std::vector<int> v;
};
int main(int argc, const char* argv[]) {
cls x, y(5);
std::cout << x.v.size() << std::endl; // prints 0 <- expected 5
std::cout << y.v.size(); // prints 5
return 0;
}
Demo: http://ideone.com/30UBzS
I expected both objects to have a v of size 5. What's wrong?
Reason I want to do this is because writing separate cls() and cls(n) ctors would duplicate a lot of code.
Calling cls(5); inside of the cls::cls() constructor is not doing what you think it is doing. It is creating a temporary variable using the second cls constructor which is destroyed at ;.
You can use C++11's delegating constructors to achieve what you want:
cls() : cls(5) { }
If you don't have a compiler that supports C++11, you can pull the common initialisation out into another function, and have both constructors call that:
class cls {
public:
cls() { init(5); }
cls(int n) { init(n); }
std::vector<int> v;
private:
void init(int n) { v.resize(n); }
};
cal(5) creates a completely different object, in fact it's a temporary meaning the object will be destroyed at the end of its encapsulation expression. Or it might not be called at all due to compiler optimization.
But with that aside, the constructor call only affects the temporary and not the original object calling the constructor.
If your intention was to make the code shorter, you should create a member function that does this (assuming your compiler doesn't support C++11, in which case you could simply use the Delegating Constructor feature):
class cls
{
void resize(int n)
{
v.resize(n);
}
public:
cls() { resize(5); }
cls(int n) { resize(n); }
std::vector<int> v;
};
You should change
cls() {cls(5);}
to
cls() {v.resize(5);}
Otherwise you are creating new temporary cls in the constructor and ignoring it.
OR If you want to delegate the constructor (C++11) do it like this
cls() : cls(5) {}
// ^^ ^
// | use cls(int n)
delegated constructor are allowed only in the member initialization list of a constructor.
Here is what you need:
class cls
{
public:
cls()
:
v( 5 ){} // create v that contains 5 elements ( each initialized to 0 ) - note: this is NOT resizing
explicit cls( const int size )
:
v( size ){}
private:
std::vector<int> v;
};
Of course, if you need resizing feature on the living object, you will need a 'resize' method already mentioned in this thread.