Can constructor call another class's constructor in c++? - c++

class A {
public:
A(int v) {
_val = v;
}
private:
int _val;
};
class B {
public:
B(int v) {
a = A(v); // i think this is the key point
}
private:
A a;
};
int main() {
B b(10);
return 0;
}
compiler says:
test.cpp: In constructor ‘B::B(int)’:
test.cpp:15: error: no matching function for call to ‘A::A()’
test.cpp:5: note: candidates are: A::A(int)
test.cpp:3: note: A::A(const A&)
I've learned Java, and I don't know how to deal with this in C++.
Searching for a couple days, plz tell me can C++ do this?

You need to use a Member Initialization List
B(int v):a(v)
{
}
With:
B(int v)
{
a = A(v); // i think this is the key point
}
a is being assigned a value and not being initialized(which is what you intend), Once the body of an constructor begins {, all its members are already constructed.
Why do you get an error?
The compiler constructs a before constructor body { begins, the compiler uses the no argument constructor of A because you didn't tell it otherwiseNote 1, Since the default no argument constructor is not available hence the error.
Why is the default no argument constructor not generated implicitly?
Once you provide any constructor for your class, the implicitly generated no argument constructor is not generated anymore. You provided overloads for constructor of A and hence there is no implicit generation of the no argument constructor.
Note 1
Using Member Initializer List is the way to tell the compiler to use particular overloaded version of the constructor and not the default no argument constructor.

You have to use initialization lists:
class B {
public:
B(int v) : a(v) { // here
}
private:
A a;
};
Otherwise the compiler will try to construct an A using the default constructor. Since you don't provide one, you get an error.

Yes it can, but you haven't provided a default constructor for A(one that takes no parameters or all parameters have default values), so you can only initialize it in the initializer list:
B(int v) : a(v)
{
}
This is because before the constructor body enters, a will be constructed (or attempted to be constructed) with the default constructor (which isn't available).

Related

std::map<int, A> operator[] requires the creation of A with empty constructor

#include <map>
class B {
public:
B() {}
};
class A {
public:
A(B b) {
}
};
int main()
{
std::map<int, A> list;
list[0] = A(B());
return 0;
}
The compiler complains that A should have a no-parameter constructor like this: A(){} because of the line list[0] = A(B());. I guess that list[0]; first createas a default A object and then executes the operator=(const A& a) on it so it can copy the A(B()); object.
However I don't want to create a default no-parameter constructor for my A class because it really should be initialized with a B object.
I managed to overcome this by doing
list.insert(std::pair<int, A>(0, A(B()));
Then I noticed that the following line:
A a = list[0];
wouldn't give any errors. For me, A a should create a default A oject using the empty A() constructor which does not exist, then the operator= would be applied. Why this line gives no error?
A a = list[0];
doesn't use a default constructor and the assignment operator. It calls the copy constructor for your class. The copy constructor is implicitly defined.
You get this error because map<>::operator[] instantiates an instance of the value-type (using the default constructor) if the indicated key is not found in the existing object. Due to this being a run-time test map<>::operator[] has to be able to perform that action even if the key is always in fact part of the object.

C++ Primer 5ed, 7_43

Hi I have a question when doing the exercise 7.43. The question goes:
"Assume we have a class named NoDefault that has a constructor that takes an int, but has no default constructor. Define a class C that has a member of type NoDefault. Define the default constructor for C."
class NoDefault{
public:
NoDefault(int i){}
};
class C{
private:
NoDefault temp;
public:
C(int i):temp(i){}
};
int main(){
C c;
return 0;
}
Why C(int i):temp(i){} is not correct?
The error shows:
$ g++ -std=c++0x -o ex7_43 ex7_43.cpp
ex7_43.cpp: In function ‘int main()’:
ex7_43.cpp:16: error: no matching function for call to ‘C::C()’
ex7_43.cpp:12: note: candidates are: C::C(int)
ex7_43.cpp:7: note: C::C(const C&)
I know that C():temp(0){} compiles find.
Thanks!
This constructor
C(int i):temp(i){}
is not the default constructor of the class. However inside main this declaration
C c;
requires existence of the default constructor of the class. So the compiler issues an error because there is no default constructor.
On the other hand this declaration
C():temp(0){}
declares the default constructor that can be used in declaration
C c;
According to the C++ Standard (12.1 Constructors)
4 A default constructor for a class X is a constructor of class X that
can be called without an argument.
You could define the default constructor with parameters but the parameters in this case shall have default arguments. For example
C(int i = 0):temp(i){}
The above constructor is the default constructor because it can be called without arguments.
And in the exersice there is written:
Define the default constructor for C
So you could define it either like
C():temp(0){}
or like
C(int i = 0):temp(i){}
or even the following way
class C{
private:
NoDefault temp;
public:
C(int i);
};
C::C( int i = 0 ) :temp( i ) {}
That is to use the default argument in the definition of the contructor outside the class but before main.
You almost had it, but you did not define "the default constructor for C". You defined some other constructor. So, then, much like in NoDefault, C had no implicit default constructor and could not be instantiated in main through the declaration C c.
C() : temp(1337) {}
There you go.

How to pass object whose constructor consist of one argument to a function in C++? [duplicate]

This question already has answers here:
in constructor, no matching function call to
(2 answers)
Closed 8 years ago.
I have defined a class B, whose constructor accept object of other class(class A) as parameter. Class A constructor also consist of parameter. I am getting error as described below. What is the problem here?
#include<iostream>
using namespace std;
class A{
int val;
A(int val){
this->val=val;
}
};
class B{
A a;
B(A& x){
a=x;
}
};
int main(){
A tempa(3);
B tempb(tempa);
}
Error:
temp.cpp: In constructor ‘B::B(A&)’:
temp.cpp:13:9: error: no matching function for call to ‘A::A()’
temp.cpp:13:9: note: candidates are:
temp.cpp:6:2: note: A::A(int)
temp.cpp:6:2: note: candidate expects 1 argument, 0 provided
temp.cpp:3:7: note: A::A(const A&)
temp.cpp:3:7: note: candidate expects 1 argument, 0 provided
The only way to explicitly initialize a data member is in the constructor initialization list. Once you are in the body of the constructor, the member has been initialized, and all you can do is modify it. In your case, since you are not doing this, the data member would bet implicitly default constructed, but A does not have a default constructor.
You need to use the appropriate constructor in the constructor initialization list:
B(A& x) : a(x)
{
}
Here's the corrected code.
#include<iostream>
using namespace std;
class A{
int val;
public:
A(int val){
this->val=val;
}
};
class B{
A a;
public:
B(A& x):a(x) {
}
};
int main(){
A tempa(3);
B tempb(tempa);
}
Corrections are:
1. Both Constructors of A and B should be public
2. Instead of assignment, let B constructor call A's copy constructor

using this pointer in initializer list

struct T
{
int a;
};
struct C
{
T& r;
C(T& v) : r(v) {}
};
struct E : T
{
T& r;
E(T const& v) : r(*this), T(v) {} // ok
};
struct F : C, T // base order doesn't matter here
{
//F(T const& v) : C(*this), T(v) {} // error : C::r is not initialized properly
F(T const& v) : C(*static_cast<T*>(this)), T(v) {} // ok
//F(T const& v) : C(static_cast<T&>(*this)), T(v) {} // ok
};
int main()
{
T v;
F f(v);
f.r.a = 1;
}
Although using this pointer in initializer list could be problem, but I've never expected this happened to PODs and may be simply fixed by explicit cast;
Is this some compiler bug or std related problem?
The code is ambiguous.
For constructing the C base of F, the context is direct-initialization, so 13.3.1.3 applies:
c++11
13.3.1.3 Initialization by constructor [over.match.ctor]
For direct-initialization, the candidate
functions are all the constructors of the class of the object being initialized.
The implicitly-declared copy constructor is included, per 12.8:8.
The candidates for the constructor of C are C(T &) and (the default copy constructor) C(const C &), by parameter list (F). In both cases we have a reference binding (13.3.3.1.4) followed by a derived-to-base Conversion (13.3.3.1), with an additional cv-qualification adjustment in the latter case, giving overall rank of Conversion in both cases.
Since C and T are both base classes of F, but are distinct types and neither is a base class of the other, none of the clauses in 13.3.3.2:3 nor 13.3.3.2:4 apply and conversion sequences are indistinguishable.
Indeed, gcc-4.5.1 rejects the code with:
prog.cpp: In constructor 'F::F(const T&)':
prog.cpp:20:34: error: call of overloaded 'C(F&)' is ambiguous
prog.cpp:9:5: note: candidates are: C::C(T&)
prog.cpp:7:1: note: C::C(const C&)
When you try to initialize the base C of F with *this, both the compiler generated copy constructor for C and the constructor that you define taking a T& are a match as the type of *this (F) is derived directly from both C and T. Your cast resolves this ambiguity.
I am surprised that the copy constructor is a better match than the one taking T& as I would have thought that they would both be equally preferred. If the copy-constructor is chosen then the base will be initialized from itself which causes undefined behavior as the reference member will be initialized from an uninitialized reference (itself).
1)never use this in initialization list
http://msdn.microsoft.com/en-us/library/3c594ae3(v=vs.80).aspx
The this pointer is valid only within nonstatic member functions. It cannot be used in the initializer list for a base class.
The base-class constructors and class member constructors are called before this constructor. In effect, you've passed a pointer to an unconstructed object to another constructor. If those other constructors access any members or call member functions on this, the result will be undefined. You should not use the this pointer until all construction has completed.
shortly: C.r initialized by bad poiter
struct C
{
T& r;
C(T& v) : r(v) {}
};
struct E : T
{
T& r;
E(T const& v) : r(*this), T(v) {} // ok
};
You need to initialize any reference at the time of declaration but here you have just declared it. This is not allowed in C++.

OOP Constructor question C++

Let's say that I have two classes A and B.
class A
{
private:
int value;
public:
A(int v)
{
value = v;
}
};
class B
{
private:
A value;
public:
B()
{
// Here's my problem
}
}
I guess it's something basic but I don't know how to call A's constructor.
Also the compiler demands a default constructor for class A. But if A has a default constructor than wouldn't the default constructor be called whenever I declare a variable of type A. Can I still call a constructor after the default constructor has been called? Or can I declare an instance of a class and then call a constructor later?
I think this could be solved using pointers but can that be avoided ?
I know that you can do something like this in C#.
EDIT: I want to do some computations in the constructor and than initialize the classes. I don't know the values beforehand.
Let's say I'm reading the value from a file and then I initialize A accordingly.
The term you are looking for is initializer list. It is separated from the constructor body with a colon and determines how the members are initialized. Always prefer initialization to assignment when possible.
class A
{
int value;
public:
A(int value) : value(value) {}
};
class B
{
A a;
public:
B(int value) : a(value) {}
}
I want to do some computations in the constructor and than initialize the classes. I don't know the values beforehand.
Simply perform the computation in a separate function which you then call in the initializer list.
class B
{
A a;
static int some_computation()
{
return 42;
}
public:
B() : a(some_computation()) {}
}
You use an initialization list to initialize the member variables.
public:
B() : value(4) { // calls A::A(4) for value.
}
Or can I declare an instance of a class and then call a constructor later?
Yes, you can do that. Instead of (A value;) declare (A* value;), and then B's constructor will be B():value(new A(5)){}.
In the B's destructor you will have to do delete value;
I think this could be solved using pointers but can that be avoided ?
Yes. Use shared_ptr.
Try:
B() :
value(0)
{
// Here's my problem
}