I have a class with which I can create a number of objects.
class Employee{
public:
string firstName;
string lastName;
string gender;//gender - if necesary
string identificationCode;//an Id for every employee
string typeOfEmployee;//is Programmer, is Tester and so on...
string getFirstName(){ return this->firstName; } //show the name
string getLastName(){ return this->lastName; }//show the name
string getGender(){ return this->gender; }//show the gender - if necesary
string getID(){ return this->identificationCode; }//show ID
string getTypeOfEmployee(){ return this->typeOfEmployee; }//show type of job
};
class Programmer : public Employee{
public:
vector<string> knownLanguages;//array of known programming languages
unsigned int countProgrammers;
}programmer[5];
Programmer::Programmer()
{
countProgrammers++;
}
int main(){...
switch (checkJob(getTokens[3]))
{
case 1:
Programmer programmer[counter];//this is error = expression must be a value
programmer[counter].identificationCode = getTokens[0];
programmer[counter].firstName = getTokens[1];
programmer[counter].lastName = getTokens[2];
programmer[counter].typeOfEmployee = getTokens[3];
programmer[counter].knownLanguagessplitString(getTokens[4], SecondDelimiter);
//cout << programmer[counter].firstName<<" " << programmer[counter].lastName<<" with ID: " << programmer[counter].identificationCode<<" is a "<<programmer[counter].typeOfEmployee<<" and knows " << endl;
counter++;
break;
...}
And I'll want to use a counter, that, when a new object is being created, or when I'm using a flow control structure to add more details to an object, whatsoever, I want to increment it.
My preference is that I want to keep it inside the class.
So far I've defined countProgrammers, but because I'm using programmer[1] and so on, it would be a different value for each Programmer I create.
Is there a way I keep the variable inside the class, but actively show me the number of total objects I create, if I'll call it like
cout<<programmer.countProgrammers; (this is not right because of the way I've defined the class, the correct way should be cout<<programmer[1].countProgrammers;, but it will show a different value for wach object created, for example, for third object it will be 3 and so on)//resolved
You would have to declare the variable as static
static unsigned int countProgrammers;
Then in the body of your constructor
Programmer::Programmer()
{
++countProgrammers;
}
That way every time a Programmer is constructed that variable will increment.
To print this value you would say
std::cout << Programmer::countProgrammers << std::endl;
Related
I encountered a strange problem, at times, at no. When I read data from a file to insert into the map, data read from file be attached to a struct type is TradeRecord and then insert to map. But when I init object order_tmp I don't assign value 0 to it so have some field in TradeRecord don't have in the file be assign junk value from c++ compiler.
//struct TradeRecord
struct TradeRecord
{
int order; // order ticket
int login; // owner's login
char symbol[12]; // security
int digits; // security precision
int cmd; // trade command
int volume; // volume
//---
__time32_t open_time; // open time
int state; // reserved
double open_price; // open price
double sl,tp; // stop loss & take profit
__time32_t close_time; // close time
int gw_volume; // gateway order volume
__time32_t expiration; // pending order's expiration time
char reason; // trade reason
char conv_reserv[3]; // reserved fields
double conv_rates[2]; // convertation rates from profit currency to group deposit currency
// (first element-for open time, second element-for close time)
double commission; // commission
double commission_agent; // agent commission
double storage; // order swaps
double close_price; // close price
double profit; // profit
double taxes; // taxes
int magic; // special value used by client experts
char comment[32]; // comment
int gw_order; // gateway order ticket
int activation; // used by MT Manager
short gw_open_price; // gateway order price deviation (pips) from order open price
short gw_close_price; // gateway order price deviation (pips) from order close price
double margin_rate; // margin convertation rate (rate of convertation from margin currency to deposit one)
__time32_t timestamp; // timestamp
int api_data[4]; // for api usage
TradeRecord *__ptr32 next; // internal data
};
//code read data from file
while (file.good())
{
std::getline(file, line_str);
boost::split(fields, line_str, boost::is_any_of(k_delimiter));
// line don't enough data
if (fields.size() < k_line_fields)
{
LOG(DEBUG) << m_log_tag << "Ignore line " << line << ", not enough data: " << line_str;
line++;
continue;
}
LOG(DEBUG) << m_log_tag << "Data line " << line << ": " << line_str;
TradeRecord order_tmp;
order_tmp.login = atoi(fields[0].c_str());
order_tmp.order = atoi(fields[1].c_str());
strncpy_s(order_tmp.symbol, _countof(order_tmp.symbol), fields[2].c_str(), _TRUNCATE);
order_tmp.volume = atoi(fields[3].c_str());
order_tmp.cmd = atoi(fields[4].c_str());
order_tmp.open_price = atof(fields[5].c_str());
order_tmp.margin_rate = atof(fields[6].c_str());
order_tmp.open_time = atoi(fields[7].c_str());
list_open_order.insert(std::make_pair(order_tmp.order, order_tmp));
LOG(DEBUG) << std::fixed << "for test, read open order: " << order_tmp.order << ", swap=" << order_tmp.storage;
line++;
}
Like you can see, in TradeRecord has so many fields but in my file not enough, so c++ auto assign value for these(-92559631349317830000000000000000000000000000000000000000000000.000000 something like this)
But I do not understand why this problem is when not because sometimes it is normal
You should not use a variable without giving it a default value.
In C++ (unlike some other programming languages like Java) do not auto-initialize variables. So in your case, the integer will be in the stack with the value of whatever random data that was there.
I don't really understand your question, but when the compiler gives your variable a random number like 9255698272838000000, it's because you either didn't give this variable an initial value or assigned it to another variable that you didn't give an initial value.
By default, the compiler just allocates memory for the struct's members (or for any variable you create). It does not assign a value to them until you explicitly tell it to do so. For example,
int i;
allocates an integer but does not give it a value. Because your computer's memory is constantly being passed around (but not zeroed-out) as programs execute and terminate by the operating system, the variable can contain literally any value before you assign it one. It is simply a region of memory, and it will probably contain whatever value it had when it was last used by a (different) program.
The following code:
int i = 0;
will allocate a variable and assign it a value.
If you initialize your struct like so:
traderecord order_temp = {};
the compiler will automatically zero-out your structure so all of its members are equal to zero. Then you can simply assign values to each member as it becomes necessary.
I am new to computer science and I guess this has something to do with hash function.
I have a class in cpp:
class Car{
public:
int fleetId;
OwnershipEnum owner;
int buildDate;
bool hasFourDoors;
... with many other members
};
Now, my problem is, how to 'scientifically' generate an integer key based on the 4 members I list?
I can think of a simple way, 10000*int(fleetId) + 1000 * int(owner) + 100Ă—int(buildDate) + int(hasFourDoors)
I think ideally the key is continuous, so I can store all the Car objects in an array and use this generated key to DIRECTLY access the car object.
***** as per the comments: the cars are all different, there is no identical cars ********
***** these four members are static: they won't change after being created *****
Can anyone point me to the right solution here?
Thanks
You can build a method to get it, using std::hash:
Its just an easy example.
std::size_t CarHash(const Car& car)
{
std::size_t h1 = std::hash<int>{}(car.fleetId);
std::size_t h2 = std::hash<int>{}(int(car.owner));
std::size_t h3 = std::hash<int>{}(int(car.isGoodCondition));
std::size_t h4 = std::hash<int>{}(int(car.isBooked));
return h1^(h2 << 1)^(h3 << 2)^(h4 << 3);
}
The combination of these members is not enough to uniquely identify a car: Imagine two cars having the same fleetId (because of being part of the same fleet), the same owner, and both being booked and in good condition. This would result in the same id if you calculate it based on these properties. As suggested by #jsheeran, you can use the license plate as an unique identifier.
Otherwise, add another member for id to your car class and have a static variable for a global, increasing key on every constructor call of car. However, be aware that this is only a sample implementation and you might want to have another class for managing the keys, because this implementation will never "free" keys.
class Car{
public:
Car() : id(++nextId) {}
const unsigned id;
private:
static unsigned nextId;
};
unsigned Car::nextId = 0U; // initialize in your cpp using the cars
int main()
{
Car a;
Car b;
Car c;
std::cout << a.id << b.id << c.id; // will print 012
}
Another suggestion would be to use GUIDs. Depending on your platform or used libraries, you can find a solution here for example: https://msdn.microsoft.com/en-us/library/ms688568(VS.85).aspx
Let assume you want a key without collision and all field can take any value in their range, you'd have to use a sizeof(int) + sizeof(OwnershipEnum) + 2 bits key to prevent all collisions, or 66 bits. It can be considered acceptable and computed like this:
struct key {
int fleetId;
OwnershipEnum owner;
char bools;
key(Car _myCar) :
fleetId(_myCar.fleetId),
owner(_myCar.owner),
bools(!!_myCar.isGoodCondition & !!_myCar.isBooked << 1 )
{}
bool operator ==(key other) { return fleetId == other.fleetId && owner == other.owner && bools == other.bools; }
};
then test like this:
Car first{1, (OwnershipEnum)2, false, true};
Car second{1, (OwnershipEnum)2, false, true};
Car third{8, (OwnershipEnum)1, true, true};
key k1{first}, k2{second}, k3{third};
std::cout << (k1 == k2) << "\n"; //true
std::cout << (k2 == k3) << "\n"; //false
std::cout << (k3 == k1) << "\n"; //false
full example program: http://cpp.sh/2vv2a
It's obviously a wrong assumption but you can try to reduce the key size if you can make all possible value for fleetId fit in 16 bits or shorten OwnershipEnum as for example
I'm really close to finishing my project, but i'm running into an error that I just can't wrap my head around.
It's telling me to use & sign to create a pointer to member.
void Inventory::eat(string food){
//takes in the string stores it in temp string call isitemin inventory to return an int
//use that int to return isEdible, int = 2 means your checking at pos 2
//if edible remove from inventory and add 2hp
string tempString = food;
int checker=isItemInventory(tempString);
bool edible = inventory[checker].getEdible;
if (!edible){
cout << "you can't eat " + food << endl;
}
else//ended here for now
So basically i have an eat function that takes in a string, it stores the string in tempstring and then uses isItemInventory() to return a number. This number tells us where abouts in the vector "inventory" that the item were trying to eat is located. Once we have that number we create a local boolean and call getEdible on the item. this should return true or false but instead i'm getting an error about using a pointer ? can anyone help me out ?
You probably want:
bool edible = inventory[checker].getEdible();
// ^^ parentheses are needed to call a function
I am running into the problem of when inserting elements into a map, I assume that every time I put a new object into it, the previous one is overwritten. Whenever I go to print out the contents of my map, only the most recent item I added is printed. I have two classes, a Recipe class and an Ingredient class. My recipe has a map<Ingredient*, int> which holds and object and its quantity.
Recipe::Recipe(){
title = "";
ingredients;
}
void Recipe::insertIngredient(Ingredient* item, int quantity){
ingredients.insert( make_pair( item, quantity ) );
}
Ingredient::Ingredient(){
name = "";
unit = "";
}
I have getters and setters for each class that I use to initialize variables and to print out the contents, but whenever I print the contents of my Recipe's map only the last item I put into it is printed out. The following is in my main function to print out the map.
map<Ingredient*, int> tempIngredients = tempRecipe->getIngredients();
map<Ingredient*, int>::iterator ingredientIt;
for (ingredientIt = tempIngredients.begin(); ingredientIt!= tempIngredients.end(); ingredientIt++) {
Ingredient* tempIngredient = ingredientIt->first;
int quantity = ingredientIt->second;
cout << "\n" << tempIngredient->getName() << " " << tempIngredient->getUnit() << " " << quantity << flush;
}
My output is currently the following:
unbleached wheat blend flour C. 1
Which is the igredient's name, unit, and quantity(value from the map) of the last element I added.
You are using a pointer for the map key without implementing a comparison operator.
You would be much better off using an Ingredient object and implement operator<.
For example,
class Ingredient {
public:
bool operator<(const Ingredient & b) const {
return getName() < b.getName();
}
// Rest of class methods data etc...
};
std::map<Ingredient, int> ingredients;
How are you calling insertIngredient? Since your map is keyed by Ingredient*, each entry must be a unique Ingredient object (by new or off the stack) or the keys will clash.
The real question is why are you keying on a pointer? Per #GWW's answer, a better solution would be to store Ingredient values and create a custom comparator function for them.
At the moment I am using a vector to store pointers to the object every time one is made, but that feels a little silly. There's probably a better way, but I haven't found it.
What I'm doing: Example usage:
The problem:
If I want to retrieve a certain Date I have to go over all items in the vector to see if RecPaymentsStack.stackDate matches the date the user requested.
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
I'm probably unnecessarily complicating things (something I do a lot) so an explenation on how something like this should be done would be very nice.
Detailed info: (in case I was being too vague)
The below example is supposed to resemble a calendar that can hold certain items (RecPayments) and those items are grouped by their date (RecPaymentsStack).
struct RecPayments
{
std::string name;
Date* date;
float cost;
};
struct RecPaymentsStack
{
Date* stackDate; //This stack's date
RecPayments * thePaymentItem; //Hold pointer to the actual item
};
And here's how I'm currently storing them
std::vector<RecPaymentsStack*> RecPaymentsVector; //This vector will hold pointers to all the Recurring Payments
void addRecurring(std::string theDate,std::string theName,float theCost)
{
//New recurring payment
RecPayments * newPaymentItem = new RecPayments;
//Set recurring payment properties
newPaymentItem->name = theName;
newPaymentItem->date = new Date(stringToChar(theDate));
newPaymentItem->cost = theCost;
//Add recurring payment to stack
RecPaymentsStack * addToStack = new RecPaymentsStack;
addToStack->stackDate = new Date(stringToChar(theDate));
addToStack->thePaymentItem = newPaymentItem;
//Add pointer to RecPaymentsStack to vector
RecPaymentsVector.push_back(addToStack);
}
So to retrieve the items for a given date, I am currently going over all pointers in the vector to see if the "stackDate" property matches the requested date, and if so I use the "thePaymentItem" property to show the actual item.
void getItemsNow(Date requestedDate)
{
std::cout << "Showing Dates for " << requestedDate << std::endl;
unsigned int i;
for(i=0;i<RecPaymentsVector.size();i++) //Go over all items in vector
{
Date dateInVector(*RecPaymentsVector[i]->stackDate); //Get the date from the vector
if(dateInVector == requestedDate) //See if Date matches what the user requested
{
//Date matched, show user the item properties.
std::cout << "Date: " << dateInVector <<
" has name: " << RecPaymentsVector[i]->thePaymentItem->name <<
" and price " << RecPaymentsVector[i]->thePaymentItem->cost <<
std::endl;
}
}
}
3 problems with this:
Going over all items in the vector is highly inefficient if I only
need a couple of pointers
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
All of this feels extremely silly to begin with.. there's probably a much easier/professional way to do this but I can't find out what, probably because I'm still thinking like a PHPer.
So the general idea here is that I end up doing something like (silly example)
for each RecPaymentsStack->stackDate //For each unique Date, show it's children items.
{
cout << "The Date is " CurrentRecPaymentsStack->stackDate and it holds the following items:
for each CurrentRecPaymentsStack->thePaymentItem //This would now be an array of pointers
{
cout << "item name " CurrentRecPaymentsStack->thePaymentItem->name << " with cost " << CurrentRecPaymentsStack->thePaymentItem->cost << endl;
}
}
Which would basically go over all the unique "RecPaymentsStack" objects (unique determined by it's "Date" property) and for each Date it would then show it's "children" from the RecPayments struct.
And there has to be some way to search for a particular date without having to go over all the available ones.
Rather than using a vector to manage your items, you should replace your RecPaymentsStack instance with a std::multimap. The key type is your Date structure, the value type is RecPayments (which I would change to the singular form RecPayment). Small example (untested):
typedef std::multimap<Date, RecPayment> RecPaymentsByDateMap;
typedef std::pair<RecPaymentsByDateMap::iterator,
RecPaymentsByDateMap::iterator>
RecPaymentsByDateMapIters;
RecPaymentsByDateMap payments_by_date;
RecPaymentsByDateMapIters findByDate(Date date) {
return payments_by_date.equal_range(date);
}
...
// find all payments with the given date
RecPaymentsByDateMapIters iters = findByDate(...);
for (RecPaymentsByDateMap::iterator it = iters.first;
it != iters.second;
++it)
{
std::cout << "Payment " << it->second.name << std::endl;
}
I might design it like this -- this is just a loose idea, details should be adjusted according to your requirements:
#include <deque>
#include <map>
#include <string>
struct RecPayment
{
std::string name;
Date date;
float cost;
};
struct RecPaymentsStack
{
Date stackDate;
std::deque<RecPayment> thePaymentItem;
bool operator<(RecPaymentsStack const & rhs) const
{
return stackDate < rhs.stackDate;
}
explicit RecPaymentsStack(Date const & d) : stackDate(d) { }
};
typedef std::multimap<RecPaymentsStack> PaymentsCollection;
Now you can insert elements:
PaymentsCollection payments;
{
auto it = payments.emplace(Date("..."));
it->thePaymentItem.emplace_back(Payment{name1, date1, cost1});
it->thePaymentItem.emplace_back(Payment{name2, date2, cost2});
it->thePaymentItem.emplace_back(Payment{name3, date3, cost3});
}