cat::cat (int inputHeight)
height = inputHeight;
^^^^^^^^^^^^^^^^^^^^
} // this is assignment
this is assignment to already created objects.
The rule is as follows: if you don't initialize instances explicitly in ctor
initialization list then
Default ctor
is called
You eventually assign to already default constructed objects in ctor
body.
Thus you face penalty of having additional calls if you don't initialize in initialization list.
C++ Standard n3337 § 12.6.2/10 Initializing bases and members
In a non-delegating constructor, initialization proceeds in the
following order:
— First, and only for the constructor of the most derived class (1.8),
virtual base classes are initialized in the order they appear on a
depth-first left-to-right traversal of the directed acyclic graph of
base classes, where “left-to-right” is the order of appearance of the
base classes in the derived class base-specifier-list.
— Then, direct base classes are initialized in declaration order as
they appear in the base-specifier-list (regardless of the order of the
mem-initializers).
— Then, non-static data members are initialized in the order they were
declared in the class definition (again regardless of the order of the
mem-initializers).
— Finally, the compound-statement of the constructor body is executed.
[ Note: The declaration order is mandated to ensure that base and
member subobjects are destroyed in the reverse order of
initialization. — end note ]
Here is a code demo.
–
public:
twoCats (const cat& theFirstCat, const cat& theSecondCat)
: firstCat (theFirstCat), secondCat (theSecondCat)
The important part here is the colon after the constructor :
. It starts the member initialization list, which is the place where, if possible, all your class data members should be initialized.
Initialization of data members is quite a complex issue in C++, I suggest you google it.
In particular, since you have two members of class type, the compiler, no matter what, tries to initialize them in your constructor. It does so for every cat, which probably is the reason you get the error message block twice. In its default, the compiler tries to initialize your cat data members using a default constructor, i.e. one without arguments. Unfortunately, cat
does not have a default constructor, since you declared one with one argument. In other words, each cat has to be initialized with one argument (or copied, or moved in C++11).
I do not recommend declaring an additional constructor to cat
without arguments: It seems that there is no "default hight" of a cat, and the -1
suggested by another answer is very strange: It doesn't seem to construct a valid object, and you'd have to check for this default value before using any of cat
's member functions.
EDIT: This is from a format point of view. As for the semantics of your program, it might be wrong to copy the cats. Maybe you do need a reference (or a pointer) to the objects you initialized your twoCats with, maybe not.
–
Both cat instances have to be initialized, at the point when they start existing.
To avoid this you can defer each instance creation to when you need it.
A simple and safe way to do that is to use a std::vector
to hold the instances.
class cat
private:
int height;
public:
cat (int inputHeight);
cat::cat (int inputHeight)
height = inputHeight;
#include <vector>
#include <utility>
class twoCats
private:
std::vector<cat> cats_;
public:
twoCats (cat theFirstCat)
{ cats_.push_back( std::move( theFirstCat ) ); }
void addSecondCat (cat theSecondCat)
{ cats_.push_back( std::move( theSecondCat ) ); }
int main() {return 0;}
Alternatively, you might use boost::optional
.
Or allocate the instances dynamically (use a smart pointer such as unique_ptr
to manage lifetime then).
Or, let cats be default-constructible.
As noted by "thang" in a comment, the original design does not guarantee that a twoCats
has two cats. It can have just one cat, or three or more cats. So it would be a good idea to change the design.
For example, have a constructor that takes two cat arguments, or cat heights.
Or for another example, changing the name of twoCats
.
–
–
–
–
As name of your class (twoCats) states it represents two cats always. These kittens can be alive, dead or even not yet born. But it shall be two of them.
Your design is wrong in the sense that either:
cat
should be able to represent non-born cat (so it should have
public default constructor setting the object into non-born state initially) or
your twoCats constructor shall accept exactly two cats at the very beginning.
–
–