I have a homework problem which I don't quite understand.
Add three constructors to the class Critter. Each constructor should
also print a simple informational message on the screen such that one
can see when and which constructor has been called. You should be able
to create an instance of the Critter class 1) without supplying any
properties (which should set the name to “default critter”, the height
to 5 and the rest to 0), 2) by only supplying a name as parameter
(which should set the height to 5 and the rest to 0), and also 3) by
supplying name, hunger, boredom and height all as parameters. You
should also be able to create an instance of the Critter class without
specifying the height. If the height is not supplied, the critter has
the default height of 10. Write a test program which creates four
instances of the Critter by using these three different constructors
(the last one in two ways). Set their hunger levels to 2 by using
appropriate method and/or constructor calls. The critters’ properties
should then be printed on the screen.
Okay, so first I created a class Critter then I added 3 constructors in it as it is described in the points 1, 2 and 3. Then I created an object or instance(they are the same thing right?). After that I created another object and created another constructor. The problem is, I am lost at the last 3 sentences:
Write a test program which creates four
instances of the Critter by using these three different constructors
(the last one in two ways). Set their hunger levels to 2 by using
appropriate method and/or constructor calls. The critters’ properties
should then be printed on the screen.
How do I create 4 instances of the Critter by using those three different constructors?
This may sound like a dumb question, but I have never worked before with classes. I am a fan of procedural programming.
This is my code:
Critter.h
class Critter {
// The following data members are private
private:
std::string name;
int hunger, boredom;
double height;
public:
Critter();
Critter(std::string& newname);
Critter(std::string& newname, int newhunger, int newboredom, double newheight);
Critter(std::string& newname, int newhunger, int newboredom);
};
and in another file I wrote:
Critter.cpp
#include <iostream>
#include "Critter.h"
using namespace std;
Critter::Critter() {
name = "default critter";
height = 5.0;
hunger = 0;
boredom = 0;
cout << "First with no properties." << endl;
}
Critter::Critter(string& newname) {
name = newname;
height = 5.0;
hunger = 0;
boredom = 0;
cout << "Only name as a parameter." << endl;
}
Critter::Critter(string& newname, int newhunger, int newboredom, double newheight) {
name = newname;
height = newheight;
hunger = newhunger;
boredom = newboredom;
cout << "All as parameters." << endl;
}
Critter::Critter(string& newname, int newhunger, int newboredom) {
name = newname;
height = 10.0;
hunger = newhunger;
boredom = newboredom;
cout << "All as parameters." << endl;
}
and the main file:
#include <iostream>
#include "Critter.h"
using namespace std;
int main() {
Critter first_instance, second_instance;
string name;
int hunger, boredom;
double height;
return 0;
}
Looking forward to your suggestions/answers.
Thank you
You have created 4 constructors, but they want you to have 3, the last of which should be used in 2 ways. The first two are fine, what they want you to do is to merge your third and fourth constructor into a single one by using default arguments for functions. Like this:
Critter::Critter(string& newname, int newhunger, int newboredom, double newheight = 10.0) {
name = newname;
height = newheight;
hunger = newhunger;
boredom = newboredom;
cout << "All as parameters." << endl;
}
This way it's a single constructor, but you can call it in two ways:
either with all the arguments, including newheight, or
by providing only the first three, and then newheight will have the
default value of 10.0.
EDIT to answer the question in a comment:
How do you create 4 instances using these 3 constructors?
The line
Critter my_first_critter;
will create an object of class Critter called my_first_critter, with no arguments, which means that the compiler will select the first constructor, and you'll read "First with no properties.". Instead, a line like
Critter my_second_critter("John");
will create a new object of class Critter, called my_second_critter, and since there's a string argument the compiler will select the second constructor, so that you'll read "Only name as a parameter.". Then, a line like
Critter my_third_critter("James", 2, 3, 5.5);
(notice the fourth argument!) will create one more object, again of class Critter and called my_third_critter, and since there are four arguments, of type: string, int, int, double, the compiler will call the third constructor and you'll read "All as parameters.". Finally, a line like
Critter my_fourth_critter("Peter", 2, 3);
(notice the fourth argument is missing!) will call the same function, because in this case the default argument kicks in. The compiler will still match this call to the third constructor (so that you will read, again, "All as parameters."), but in this case the height will be the default value of 10.0, as the programmer that created the object (you) didn't specify the value.
Setting the default value of height to 10.0 is useful if it happens very often that the height is 10.0 and you don't want to waste time specifying this number every time you create a Critter (which would also be error-prone: think of typos or getting confused...). Still, if you need a value other than 10.0, you can easily provide it. And since it's just one constructor, and not 2 separate ones, you have less code to manage. You could, of course, avoid using default arguments and write 2 constructors (as you have done), but suppose you find a bug in your third one: most certainly you'd have to fix it in your fourth one as well. What if you forget to do it? If you have just one function your code is easier to manage. Also, consider that you can provide more than one default argument per function. If you had to do without default arguments, you'd have to create a lot of copies. It wouldn't scale well.
Related
Take a look at this code, it has a class that, when a new object is created, will give it a random number for 'lvl' between 1 and 100. After the class, I define some objects using class instances.
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
class newPokemon {
public:
int lvl;
newPokemon() {
lvl = (rand() % 100 + 1);
};
void getLevel() {
cout << lvl << endl;
};
};
newPokemon Gengar;
newPokemon Ghastly;
newPokemon ayylmao;
};
What I want to do next is allow the use to define new pokemon (objects) by asking them for a name. This means, however, I need to create objects dynamically. For example,
Program asks user for a name
Name is then saved as an object from the class newPokemon
Program can use that name to run other functions from the class, like getLevel.
How am I able to do this? I, of course, get that I can't do it like the hard coded ones, as I cannot reference user input as a variable name, but is there some way to do what I am asking by manipulating pointers or something?
Use std::map to hold your objects according to their names:
std::map<std::string, newPokemon> world;
You must make sure that your objects get added to the map immediately after being created.
std::string name;
... // ask the user for a name
world[name] = newPokemon();
std::cout << "Your level is " << world[name].getLevel() << '\n';
You probably just want each Pokemon to have a name property (member variable/field). Just make a bunch of Pokemon with the name filled in.
Scenario
I am in the process of learning C++, so please forgive my naivety. I have attempted to build my own class, objects and methods - each of which seem to work as expected. However I am running into issues with what seems to be uninitialized storage (and possibly the use of local objects?) however I would like to know how to fix it, if indeed it is meant to be, or an alternative. My current train of thought is that the object needs to be passed...however that could be way off...
Code
//header
class Car{
public:
USHORT GetMin();
void SetMin(USHORT min);
private:
USHORT itsMinPrice;
};
USHORT Car::GetMin(){
return itsMinPrice;
}
void Car::SetMin(USHORT min){
itsMinPrice = min;
}
-
void StartingPrices(){
Car Mercedes;
std::cout << Mercedes.GetMin() << "\n";
Mercedes.SetMin(50);
std::cout << Mercedes.GetMin()<< "\n";
}
int main(){
float input;
Car Mercedes;
Mercedes.SetMin(100);
StartingPrices();
std::cout << Mercedes.GetMin() << "\n";
std::cin >> input;
return 0;
}
Expected output
100, 50, 50
Actual output
debug win32 - 52428, 50, 100
release win32 - 0, 50, 100
In your StartingPrices function, the Mercedes object you call GetMin is created on the line before, i.e., not the same object as the one you create in the main function.
That means that the object do not yet have itsMinPrice set to anything, hence the value will be garbage (that is, a value which you don't really have control over), in this case 52428 in debug and 0 in release.
What I think you wish to do is pass a reference of the Mercedes object from the main function into the StartingPrices function:
void StartingPrices(Car& mercedes){
std::cout << Mercedes.GetMin() << "\n"; // Here the GetMin method will return 100.
...
}
int main(){
....
Car Mercedes;
Mercedes.SetMin(100);
StartingPrices(Mercedes);
....
}
Its also a good idea to set the default value of the members in the constructor of the class.
In your Car class you do not initialize your member variable itsMinPrice except when you call SetMin, this means there is a risk that you will use an uninitialized Car instance if you forget to call SetMin on it. Normally it is good to have initialization in a constructor of the class with some value e.g.
Car() : itsMinPrice(0) {
}
or create a constructor that takes an initial value
Car(USHORT minValue) : itsMinPrice(minValue) {
}
I'm having a little difficulty in calling a class constructor in the int main() part of my code.
It is a constructor with an array of strings as the argument.
I know that, when calling a constructor, one can either set default arguments or no arguments at all, and that an object is required to call the constructor (along with the arguments, we want to give in it). But I still don't understand how to call this, although I've tried many different methods.
This is my code:
#include <iostream>
#include <string>
using namespace std;
enum player_position{ GoalKeeper, Midfielder, Defender, Striker };
class Football_Player
{
private:
string Name;
int Age;
int Points;
player_position Ppos;
public:
Football_Player(string _name = "aname", int _age = 20, int _points = 50, player_position _ppos = Striker)
{
Name = _name;
Age = _age;
Points = _points;
Ppos = _ppos;
}
Football_Player(string str[4]) // <---- "This Constructor is the one , i can't seem to call into the main()."
{
cin >> str[0];
Name = str[0];
cout << Name;
cout << str[0];
int a = atoi(str[1].c_str());
cout << a;
int b = atoi(str[2].c_str());
cout << b;
str[3] = Ppos;
}
};
int main()
{
// Please don't take any of the info as biased, these are just random.
Football_Player("Messi", 20, 50, Striker);// This one is the previous constructor with the default arguments and this one seems to be working.
Football_Player (); // Trying to call that constructor
Football_Player object1("Messi"); // Trying to call that constructor
Football_Player object2("Ronaldo", 25, 50, Striker); // Again trying to call that Constructor
Football_Player object3(str[0]); // And Again . . . .
system("pause");
return 0;
}
As you declared 4 defaults in your first CTor, your call Football_Player object1("Messi"); will actually call that one, and leave
age = 20
points = 50
position = Striker
It's plain wrong that you "either must give all params, or none". For all arguments you give, position matters. In your example: If you give 2 arguments, you give the name and the age. There is no way to give points and position only. Also a call like Football_Player object1("Messi",,,Midfield); is not possible.
The second constructor always needs an array of 4 strings. Nothing more, nothing less. But I would recommend to remove that one, as with no tricks you could also give it a pointer to a string, resulting in a crash.
I'm writing the following program.
Write a class called CAccount which contains two
private data elements, an integer accountNumber
and a floating point accountBalance, and three
member functions:
A constructor that allows the user to set
initial values for accountNumber and
accountBalance and a default constructor
that prompts for the input of the values for
the above data members.
A function called inputTransaction,
which reads a character value for
transactionType ('D' for deposit
and 'W' for withdrawal), and a floating point
value for transactionAmount, which
updates accountBalance.
A function called printBalance, which
prints on the screen the accountNumber
and accountBalance.
--
#include <iostream>
using namespace std;
class CAccount{
public:
CAccount(){
setValues(2, 5);
printBalance();
inputTransaction();
printBalance();
}
void setValues(int aN, int aB);
void inputTransaction();
void printBalance();
private:
int accountNumber;
float accountBalance;
};
void CAccount::setValues(int aN, int aB){
accountNumber = aN;
accountBalance = aB;
}
void CAccount::inputTransaction(){
char transactionType;
float transactionAmount;
cout << "Type of transaction? D - Deposit, W - Withdrawal" << endl;
cin >> transactionType;
cout << "Input the amount you want to deposit/withdraw" << endl;
cin >> transactionAmount;
if(transactionType == 'D'){
accountBalance += transactionAmount;
}
else if(transactionType == 'W'){
accountBalance -= transactionAmount;
}
}
void CAccount::printBalance(){
cout << "Account number : " << accountNumber << endl << "Account balance : " << accountBalance << endl;
}
int main ()
{
CAccount client;
}
I don't understand this part :
1. A constructor that allows the user to set
initial values for accountNumber and
accountBalance and a default constructor
that prompts for the input of the values for
the above data members.
What exactly is the difference between a constructor and default constructor, I'm kinda confused on this step.
Other than that, I would like to ask people with more experience to tell me any tips I should follow when coding with classes and which mistakes to avoid (this is my first class I ever wrote in C++).
A Default constructor is defined to have no arguments at all as opposed to a constructor in general which can have as many arguments as you wish.
Your second question is far too general to be answered here. Please turn to the many many sources in the net. stackoverflow is for specific questions not for tutorials.
If you don't define a constructor for a class, a default parameterless constructor is automatically created by the compiler. Default constructor is created only if there are no constructors. If you define any constructor for your class, no default constructor is automatically created.
A default constructor is one that doesn't need to be given arguments, either because it doesn't have any, or the ones it has have default values. Such constructors are special in the sense that say Type var; or Type var[10];
or new Type(); invoke and require them.
See how you've written void CAccount::setValues(int aN, int aB)? If you change setValues to CAccount it becomes another constructor with 2 int arguments... that's a user-defined non-default constructor and satisfies your requirements.
As is, because you only have one constructor that doesn't take any arguments but reads inputs from stdin, you're forcing users to use that constructor, read inputs, and if you call setValues you'd be overwriting those values with the setValue arguments....
Default constructor is one type of constructor.
Where as we have other conctructors namely:
Parameterised constructor
Copy constructor
If we don't define any constructor then a default constructor is provided. But if we define any constructor then no default constructor is provided.
Default constructor doesn't take any parameter. Where as other constructors need parameter.
For your 2nd question:
If you define any constructor (parameterised or copy constructor) then you should define a default constructor also. Otherwise code like
ClassName obj = new ClassName();
will give build error. But this again depends upon your requirement and usecase.
And constructor is generally used for initialization. But you have called some functions inside constructor which is generally not done.
The default constructor is a compiler generated parameter-less constructor. You can explicitly define a constructor taking zero arguments but not everybody would call it a default constructor.
Your program should define a constructor with parameters for accountNumber and accountBalance, and a parameter-less one that prompts the user. Like this:
#include <iostream>
using namespace std;
class CAccount {
public:
/**
* Constructor prompting the user for accountNumber and accountBalance
*/
CAccount()
{
inputTransaction();
printBalance();
}
/**
* Constructor initializing accountNumber and accountBalance with parameters
*/
CAccount(int accountNumber, float accountBalance)
: accountNumber(accountNumber),
accountBalance(accountBalance)
{
printBalance();
}
void inputTransaction() { /* Implement me. */ }
void printBalance() { /* Implement me. */ }
private:
int accountNumber;
float accountBalance;
};
As you can see, I used initializers for accountNumber and accountBalance in the constructor taking those arguments. That is what you should always do.
I'm new to C++ and I'm trying to figure out this problem I'm having with my constructor for one of my classes. What happens is... all my variables are initialized properly except two (health and type).
#pragma once
#include <irrlicht.h>
#include <vector>
#include <cassert>
using namespace irr;
using namespace core;
using namespace scene;
enum
{
PLAYER = 0,
NPC = 1,
SOLDIER = 2,
CHAINGUNNER = 3
};
class Model
{
public:
Model(void);
Model(int id, std::vector<ISceneNode*> modelVec, int modType);
~Model(void);
std::vector<int> path;
std::vector<ISceneNode*> model;
int endNode;
int type;
int animate;
int health;
u32 lastAnimation;
private:
int mId;
};
#include "Model.h"
Model::Model(void)
{
//assert(false);
}
Model::Model(int id, std::vector<ISceneNode*> modelVec, int modType)
{
path = std::vector<int>();
model = modelVec;
endNode = 0;
type = modType;
animate = 0;
health = 100;
lastAnimation = 0;
mId = id;
}
Model::~Model(void)
{}
I create a model with Model soldier(id, model, SOLDIER)
Everything is set properly except type and health. I've tried many different things, but I cannot figure out my problem. I'm not sure but the default constructor is being called. It doesn't make sense because I make no called to that constructor.
Thanks,
vector<ISceneNode*> model;
model.push_back(soldierBody);
model.push_back(soldierHead);
model.push_back(soldierWeapon);
cout << "Id of char: " << id << endl;
Model soldier(id, model, SOLDIER);
modelMap[id] = soldier;
This lines:
modelMap[id] = soldier;
First default constructs the Model inside the map.
The returned reference is then used with the assignment operator to copy the value of soldier into the value contained inside the map.
To test if it is working try:
Model soldier(id, model, SOLDIER);
std::cout << "TYPE(" << soldier.type << ") HEALTH(" << soldier.health << ")" std::endl;
modelMap[id] = soldier;
std::cout << "TYPE(" << modelMap[id].type << " HEALTH(" << modelMap[id].health << ")" std::endl;
If your class is not designed to be default constructible.
Then do not have a default constructor (this will just lead to problems).
Declare a default constructor in the private part of the class (no need for a body).
Without a default constructor you will not be able to use the operator[] on map. But you can get around this by using insert:
modelMap.insert(std::map<XX, Model>::value_type(id, soldier));
From the comments, you say that you are inserting these into a map like so:
modelMap[id] = Model(id, model, SOLDIER);
std::map::operator[] requires that the mapped type be default constructible. When you call operator[] on a map, if there is no mapped value with the given key, the map default constructs a new object, maps it to the given key, and returns a reference to that object.
You can get around this by using std::map::insert():
modelMap.insert(std::make_pair(id, Model(id, model, SOLDIER));
You do:
Model soldier(id, model, SOLDIER); //1
modelMap[id] = soldier; //2
What happens here?
1. New object is created, using consructor you have provided.
2. The so-called copy-constructor copy assignment operator is called to copy soldier to modelMap[id]. You haven't defined your own copy-constructor copy assignment operator so one default is created for you by compiler, it is in most cases just copying byte-by-byte whole data-structure to the new memory address. However you have vector of pointers in your class, so compiler should call copy-constructor of vector... And I don't know (maybe someone with greater experience would know exactly what happens now) what is the result copy-constructor, I don't know if standard clearly defines 'default copy-constructor'.
So it is possible, that the whole structure is copied to the modelMap[] but with some random data.
If you create a copy-constructor (its declaration in your case will look something like Model::Model(const Model& myModel);, copy-constructor always takes reference to object of its type as an argument) If you override copy assignment operator (best, if you make both things), you have control over everything that is done while copying your object to another variable/object.
Download eg. Bruce Eckel's Thinking in C++, V. 1 [1], or search somewhere on the Net how to do it (probably this will be good, didn't read whole article, http://www.learncpp.com/cpp-tutorial/911-the-copy-constructor-and-overloading-the-assignment-operator/).
[1] Downloadable on his website, mindview.net, as a new user I can paste only one link, so cannot link it here myself :P.