I'm trying to instantiate a class within a class, so that the outer class contains the inner class.
This is my code:
#include <iostream>
#include <string>
class Inner {
private:
std::string message;
public:
Inner(std::string m);
void print() const;
};
Inner::Inner(std::string m) {
message = m;
}
void Inner::print() const {
std::cout << message << std::endl;
std::cout << message << std::endl;
}
class Outer {
private:
std::string message;
Inner in;
public:
Outer(std::string m);
void print() const;
};
Outer::Outer(std::string m) {
message = m;
}
void Outer::print() const {
std::cout << message << std::endl;
}
int main() {
Outer out("Hello world.");
out.print();
return 0;
}
"Inner in", is my attempt at containing the inner within the outer, however, when I compile, i get an error that there is no matching function for call to Inner::Inner(). What have I done wrong?
Thanks.
You could also add a constructor to Inner that takes no argument. It's implicitly trying to call it since you're not explicitly initializing
in
inOuter
. Ifin
were a pointer (Inner *in
), then it would work.Basically if you write
in C++, it will call the default constructor (
Foo::Foo()
).You need to use initialization lists to initialize class members:
(Note that I passed the strings per
const
reference, which is better than passing them by value. See this answer for how to pass function arguments.)This way you can specify exactly which constructors should be called for class members.
If you don't specify a constructor, the default one will be called implicitly. Assigning to the object later will then invoke the assignment operator and override whatever the default constructor initialized the object to. That's wasting performance at best.
Since our
Inner
doesn't have a default constructor (declaring any constructor prevents the compiler from defining a default constructor by itself), it cannot be called, so you need to specify the constructor taking a string explicitly.Edit: Note that, if you have more than one class member, they are all initialized that way, separated by commas:
Note that the order of initialization of class members is determined by their declaration order within the class definition, not by the order they appear in the initialization list. It's best to not to rely on initialization order, since changing that in the class definition would then create a very subtle bug in the constructor's definition. If you can't avoid that, put a comment besides the class members declaration:
Base class constructors are specified the same way, and they are initialized before class members, also in order of declaration in the base class list. Virtual base classes, however, are initialized before all non-virtual base classes.
Destructors, BTW, are always called in the reverse order of constructors. You can rely on that.
Since
Inner
has no default constructor, you need to initialize it explicitly. The way to do this, as @sbi pointed out, is using the initialization list in the constructor.