Reputation: 174
I am trying to simulate a certain game as an exercise (dont ask me which, you will know if you know the game), however, I just learnt objects and class on the internet and the whole thing is still so confusing to me. The following is a section of my code that is giving me an error.
The error I have is:
C:\Users\N\Desktop\Untitled1.cpp In constructor 'ekop::Moveset::Moveset()':
56 9 C:\Users\N\Desktop\Untitled1.cpp [Error] no matching function for call to 'Move::Move()'
56 9 C:\Users\N\Desktop\Untitled1.cpp [Note] candidates are:
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(std::string, int, int, int)
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 4 arguments, 0 provided
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(const Move&)
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 1 argument, 0 provided
56 9 C:\Users\N\Desktop\Untitled1.cpp [Error] no matching function for call to 'Move::Move()'
56 9 C:\Users\N\Desktop\Untitled1.cpp [Note] candidates are:
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(std::string, int, int, int)
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 4 arguments, 0 provided
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(const Move&)
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 1 argument, 0 provided
56 9 C:\Users\N\Desktop\Untitled1.cpp [Error] no matching function for call to 'Move::Move()'
56 9 C:\Users\N\Desktop\Untitled1.cpp [Note] candidates are:
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(std::string, int, int, int)
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 4 arguments, 0 provided
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(const Move&)
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 1 argument, 0 provided
56 9 C:\Users\N\Desktop\Untitled1.cpp [Error] no matching function for call to 'Move::Move()'
56 9 C:\Users\N\Desktop\Untitled1.cpp [Note] candidates are:
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(std::string, int, int, int)
14 3 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 4 arguments, 0 provided
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] Move::Move(const Move&)
11 7 C:\Users\N\Desktop\Untitled1.cpp [Note] candidate expects 1 argument, 0 provided
C:\Users\N\Desktop\Untitled1.cpp In constructor 'ekop::ekop()':
52 12 C:\Users\N\Desktop\Untitled1.cpp [Note] synthesized method 'ekop::Moveset::Moveset()' first required here
I don't know what went wrong, the code is below.
Don't tell me not to use using namespace std;
, I know I am not supposed to do that but I am not going to fix that in this program.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <string>
#include <stdio.h> /* printf, scanf, puts, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
using namespace std;
class Move
{
public:
Move(string a, int b, int c, int d)
{
name = a;
type_num = b;
power = c;
accuracy = d;
}
void setName (string a)
{
name = a;
}
void setType_num(int a)
{
type_num = a;
}
void setPower(int a)
{
power = a;
}
void setAccuracy(int a)
{
accuracy = a;
}
private:
string name, type;
int type_num, power, accuracy;
};
class ekop
{
public:
ekop()
{
Moveset moveset;
}
private:
class Moveset
{
public:
//constructor
//retrievors
private:
Move slot1, slot2, slot3, slot4;
};
};
int main()
{
//lines of code
return EXIT_SUCCESS;
}
edit 1: I had this constructor for the class Moveset, but since it didnt affect the error when I took it out, so I didnt include that in the post just now.
Moveset()
{
slot1.setName("MOVE 1");
slot1.setType_num(rand()%18);
slot1.setPower(10*(rand%15+1));
slot1.setAccuracy(5*(rand%11+10));
//repeat for the rest of the slots
}
edit 2: Now if I do this instead:
//No change before this
class Moveset
{
public:
//constructor
//retrievors
private:
Move slot1("MOVE 1", rand() % 18, 10*(rand % 15 + 1), 5 * (rand % 11 + 10)),
slot2("MOVE 2", rand() % 18, 10*(rand % 15 + 1), 5 * (rand % 11 + 10)),
slot3("MOVE 3", rand() % 18, 10*(rand % 15 + 1), 5 * (rand % 11 + 10)),
slot4("MOVE 4", rand() % 18, 10*(rand % 15 + 1), 5 * (rand % 11 + 10));
};
};
//no change after this
I get this error instead:
62 16 C:\Users\N\Desktop\Untitled1.cpp [Error] expected identifier before string constant
62 16 C:\Users\N\Desktop\Untitled1.cpp [Error] expected ',' or '...' before string constant
63 16 C:\Users\N\Desktop\Untitled1.cpp [Error] expected identifier before string constant
63 16 C:\Users\N\Desktop\Untitled1.cpp [Error] expected ',' or '...' before string constant
64 13 C:\Users\N\Desktop\Untitled1.cpp [Error] expected identifier before string constant
64 13 C:\Users\N\Desktop\Untitled1.cpp [Error] expected ',' or '...' before string constant
65 13 C:\Users\N\Desktop\Untitled1.cpp [Error] expected identifier before string constant
65 13 C:\Users\N\Desktop\Untitled1.cpp [Error] expected ',' or '...' before string constant
Upvotes: 3
Views: 4342
Reputation: 2075
Basically, you've got no default constructor for Move. To make this code work, add the following to the public section of the Move class:
Move() {
//Give fields default values here
}
When you declare a variable without initializing it, it calls the default constructor (the constructor with no arguments) to give the variable default values until it's used. Sometimes these default values are kept, sometimes you assign a new object to it.. But that's depends on what you want to do and isn't really relevant.
Edit: Okay so to elaborate, there are a couple of ways to declare/initialize variables in C++. I'll use std::string as an example, but this applies to any type (even the fundamental types, though their classes aren't defined, per se, as much as just built into the language):
std::string str1;
std::string str2 = "Two";
std::string str3("Three");
std::string str4 = std::string("Four");
str1
is just a declaration, the rest are declarations and initializations (they declare the variable, and then give it an initial value).
str1
calls the default constructor, because no initial value is provided. Therefore, the compiler needs something to assign to str1
and the default constructor provides that something.
str2
and str3
are actually different styles of the exact same call - a call to one of the parameterized std::string
constructors (namely, in this case, the std::string(const char*)
constructor). str3
is fairly self explanatory: its like a normal function call, only it's the constructor being called, not a normal function. str2
shows a funny thing about C++ - when initializing a variable with the =
sign, it calls a constructor. In this case, is calls a converting constructor, which I'll go into a little more detail about, but I'll wait till the end.
Finally, str4
, unlike the others, actually calls two constructors (making it the least efficient, technically speaking). The first one called is the std::string("Four")
, which creates an unnamed std::string
object, which is then passed to the std::string
copy constructor (which looks like std::string(std::string&)
) to create the str4
variable.
It goes like this: an unnamed std::string
object is created and given the value "Four" (std::string("Four")
). That object is then passed (by that quirky =
sign again) to the std::string
copy constructor, to copy the unnamed string object to str4
, completing it's creation. See that this method calls two constructors, creating an extra unnecessary object that's used in the creation of str4
.
Now - converting constructors. If a class defines a constructor that takes a single parameter, that constructor is a converting constructor. So basically, whenever an object of that class is initialized with a value that can be taken by a converting constructor, that value is passed to the constructor and the constructor handles it from there.
Converting constructors aren't anything special - they're just normal constructors. The only difference is that you don't need parentheses to call it when initializing, you just put the value there. Take the std::string(const char*)
constructor. This constructor acts to convert const char*
(known as a C-style string, from the days of the C language) to a std::string
object. With a converting constructor, you can put the parameter value (e.g. const char*) anywhere that a std::string
is required (in the return value of a function, for example) and it will automatically create a std::string
object from the const char*
(in case you didn't know, whenever you type something like "Hello World"
it is actually a const char*
value, though is it often converted to a std::string
by your code).
One way you can avoid creating a converting constructor while still having one argument (because automatic - a.k.a implicit - conversions can sometimes be annoying) is to put the keyword explicit
in front of the constructor declaration, which will tell the compilation not to do implicit conversions - meaning that whenever you want to convert, you must use std::string("Hello World")
rather than just "Hello World"
.
Hopefully you understand that I'm talking about, if not just let me know! By the way, I still need to verify what I've said about that =
sign, which I'll use the Visual Studio debugger to do when I get home. I will update the post to reflect my findings.
Upvotes: 0
Reputation: 145279
A MoveSet
contains four default-initialized Move
instances, but Move
has no default constructor – because you have defined a constructor, which suppresses automatic generation of a default constructor.
Since the class needs a user-defined default constructor (built in type data members will otherwise have arbitrary values), define one.
One way to define it is to provide default values for all arguments of the existing constructor, but I'd define a separate default constructor.
In passing, the existing code
Move(string a, int b, int c, int d)
{
name = a;
type_num = b;
power = c;
accuracy = d;
}
… which uses assignments to initialize members, has a problem as a general way to do this. Namely, that members of class type that can't be default-initialized, can't be initialized this way. You'd experience the same problem as above, namely error messages about lacking a default constructor.
A solution is to use a member initializer list, like this:
Move( string a, int b, int c, int d )
: name( a ), type_num( b ), power( c ), accuracy( d )
{}
There are further possible refinements, such as move
for efficiency or const
for clarity (unfortunately one has to choose between them), but the important thing is to just generally adopt this convention of using member initializer lists, which works much more generally than assignments to members.
Upvotes: 3