C++ Primer 5ed, 7_43 - c++

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.

Related

why does my class only work with two constructors c++

This does not work
When I don't have a blank constructor in my class the code will not run causing an error saying no default constructor exists for class.
#include <iostream>
class myClass
{
public:
myClass(int val)
:x(val)
{}
private:
int x;
};
int main()
{
myClass random;
return 0;
}
This works
#include <iostream>
class myClass
{
public:
myClass(int val)
:x(val)
{}
myClass()
{}
private:
int x;
};
int main()
{
myClass random;
return 0;
}
This is because when you try to instantiate the object myClass random, you are trying to invoke the default constructor which you do not have.
If you changed it to myClass random(3)( basically trying to invoke the constructor that you have), you would see that the compiler would have no problems.
If you want myClass random to compile fine, then you must have a default constructor in your class.
Once you declare a constructor in a class (any constructor), the compiler won't automatically generate a default constructor for you (this is what you're calling the blank constructor).
If you don't want to implement the default constructor (generally a good idea if you just want the default behavior), you can tell the compiler to generate it for you as of C++11.
class myClass {
public:
myClass(int val)
:x(val)
{}
myClass() = default; // the compiler handles the implementation
private:
int x;
};
In the first case you have defined a parameterized constructor. When a constructor is defined the compiler now does not automatically define a default constructor like before.
If no constructor is defined the compiler automatically defines a default constructor but if another constructor is defined the compiler will not do so.
i.e. in first case a default constructor does not exist. In the second case you have defined one and hence has no errors.
See default constructor.
If no user-declared constructors of any kind are provided for a class type, the compiler will always declare a default constructor as an inline public member of its class.
However, there's a constuctor declared in your class, thus the compiler won't declare a default constructor. You have to explicitly declare one yourself.

Constructor of the base is not made available by the using declaration [duplicate]

I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;

Constructor with default arguments can not be called when inherited [duplicate]

I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;

Inherit and overload default constructor

I've been searching for this and I'm amazed I haven't found anything. Why can't I inherit a base class constructor using using declaration and add an overload in the derived class? I'm using Visual C++ 2013, the base class constructor is ignored when default-constructing b:
error C2512: 'B' : no appropriate default constructor available
I've dealt with this by re-defining the constructors, but I don't like that. This is just a minimal example, it wouldn't bother me if I had only one base class constructor.
struct A
{
A() : a(10) {}
int a;
};
struct B : A
{
using A::A;
explicit B(int a) { this->a = a; }
};
int main()
{
B b;
}
The problem is that default-constructors are not inherited. From [class.inhctor]/p3:
For each non-template constructor in the candidate set of inherited constructors [..], a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class.
You also have a user-declared constructor that suppresses the creation of an implicit default-constructor. Just add a defaulted one to make it work:
B() = default;

Can constructor call another class's constructor in 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).