I'm doing a restaurant management program. Right now I'm trying to output private vector data and am getting stuck.
So I have a Menu.h
private:
vector<Category> categories;
vector<Menu_Item> menu_items;
vector<Recipe> recipes;
vector<Ingredient> ingredients;
vector<Order> orders;
vector<Order_Item> order_items;
And Menu.cpp
Menu.read()
Menu.show()
The read function reads from a file like this
1010 Appetizers
1901 Entrees
1576 Desserts
1320 Drinks
And stores those values into the appropriate vector, for example this one would be vector categories.
I also have a .h file for all the different types of things like, Menu_Item.h, Recipe.h, etc. And I store values into the vector like such:
menu_items.push_back(Menu_Item(meniID, catID, rID....
However in Menu_Item.h the values are
private:
int menu_item_id;
int cat_id;
int recipe_id;
string menu_item_name;
double price;
The show() function queries the user what he/she wants to see. Let's say the user wants to see a specific menu item like Onion rings. What I can't do is
if(menu_items[0].menu_item_name == "Onion Rings")
because it says that menu_item_name value is private within Menu_Item.h. How can I access the private data?
You have to make menu_items public or make a public getter function like the following.
public:
vector<Menu_Item> get_menu_items(){ return menu_items;}
Then say if you had a Menu object of this type called Menu you can do this:
if(Menu.get_menu_items()[0].menu_item_name == "Onion Rings")
The other possible option is that you make a friend class if another specific class needs access, though usually this won't be the best design decision.
In response to the comment you could do this:
for(size_t n=0, n<menu_items.size()-1, ++n){
if(Menu.get_menu_items()[n].menu_item_name == "Onion rings")
cout << "something";
}
Two options:
Declare your fields in Menu_item.h as public, not private.
Keep your fields as private, but create public getters (and setters) to access the fields.
Related
I apologize if this seems trivial, but I've searched for an answer for a while now, and I can't seem to find a solution.
I have a list of structs (TArray of structs to be exact.) that represent high scores in my game. (Each struct represents a high score, the fields are something like "Name, Date, Player Score, Game Mode etc" I use this SaveGame method to save a load my array of high scores to and from a file.
I used this with mock values and the system works, now I want to create a UMG widget that will display the list of high scores and this is where I ran into a snag.
I want to use a ListView to show each struct as a ListViewEntry. As far as I understand(I was following this tutorial), A UMG List View needs it's entry widgets to implement the IUserObjectListEntry specifically one has to implement the OnListItemObjectSet (UObject* ListItemObject) method. This method is responsible for assigning an object to the Listview entry and mapping its fields to the various visual widgets. You can see my problem now, I have a list of UStructs and this method needs a UObject pointer.
I'm really at a loss at what I need to do to make this work with a UStruct. Short of creating a dummy UObject that's pretty much identical to my struct and before passing the struct to this function I need to copy its fields into the dummy UObject and pass it instead. I think this method is very inelegant. There has to be a better way. Do you know any?
I wanted to avoid creating a dummy UObject just for the sake of passing it to this function.
I tried to use an array of UObjects instead of an array of Structs but the problem is, an array of UObjects is always an array of pointers, and when it gets saved, the pointers getting saved and not the actual data, so when it's loaded the data is useless.
Maybe there is a Struct-specific interface one can implement for a ListViewEntry widget? Or maybe there is a way to dereference the pointers of the array of Uobjects before saving them?
TL;DR
I have the following stuct:
c++
USTRUCT()
class FHighScoreEntry
{
GENERATED_BODY()
public:
//Player name
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString PlayerName;
//Player Score
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 PlayerScore;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FDateTime CurrentDateTime;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TEnumAsByte<EGameType> GameType;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 AccuracyTrialMaxTries;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 TimeTrialMaxTime;
}
In the following array;
c++
TArray<FHighScoreEntry> HighScores;
I want to show the array of high scores in a UMG ListView. The ListView requires its entries to implement the User List Object interface, which has this function:
As you can see, the event only accepts UObjects. Hence my problem.
This was asked 8 months ago, so may no longer be useful to you. But this post is the only thing I could find when searching for this issue on the Internet, so I am posting my solution for the next person researching this.
At a high level, create a UObject wrapper for the struct.
In my USaveGame class I have an array of structs because as you mentioned, an array of UObject pointers does not actually save any data. I created an UObject derived class that simply contains the same struct as the sole UPROPERTY.
UCLASS(Blueprintable, BlueprintType)
class PORTALTEST_API UHighScoreObject : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Score")
FHighScore HighScore;
};
In my Game Instance class, I have an array of pointers to this UObject
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Score")
TArray<UHighScoreObject*> HighScoreArray;
I use this array of UObject pointers for the List View of the widget.
HighScoreWidgetBlueprint
In the Save function of my Game Instance class I clear the struct of arrays and fill it with with the data contained in the array of UObject pointers. (I am only keeping the top ten high scores, so this seemed more efficient than keeping track of changes in both arrays.)
bool UMyGameInstance::SaveHighScore()
{
// Call SaveGameToSlot to serialize and save our SaveHighScoreObject with
//name HighScoreSaveSlot.sav
// Retrieve save values
SaveHighScoreObject->HighScoreArray.Empty();
for (auto HighScore : HighScoreArray)
{
SaveHighScoreObject->HighScoreArray.Add(HighScore->HighScore);
}
// Save game to file
const bool IsSaved = UGameplayStatics::SaveGameToSlot(SaveHighScoreObject,
UNIQUE_HIGHSCORE_SLOT, 0);
return IsSaved;
}
And in the Load function of my game instance I read in the array of structs and populate the array of UObjects.
bool UMyGameInstance::LoadHighScore()
{
// Try to load a saved game file with "HighScoreSaveSlot.sav if it exists
USaveGame* LoadedHighScore =
UGameplayStatics::LoadGameFromSlot(UNIQUE_HIGHSCORE_SLOT, 0);
SaveHighScoreObject = Cast<UHighScoreSaveGame>(LoadedHighScore);
//If the file does not exist, create a new one
if (!SaveHighScoreObject)
{
// Instantiate a new SaveGame object
SaveHighScoreObject = Cast<UHighScoreSaveGame>
(UGameplayStatics::CreateSaveGameObject(UHighScoreSaveGame::StaticClass()));
// Call SaveGameToSlot to serialize and save our game object with name
// "HighScoreSaveSlot.sav"
const bool IsSaved =
UGameplayStatics::SaveGameToSlot(SaveHighScoreObject, UNIQUE_HIGHSCORE_SLOT, 0);
return IsSaved;
}
else
{
for (auto HighScore : SaveHighScoreObject->HighScoreArray)
{
UHighScoreObject* HighScoreObj = NewObject<UHighScoreObject>
((UObject*)GetTransientPackage(), UHighScoreObject::StaticClass());
HighScoreObj->HighScore = HighScore;
HighScoreArray.Add(HighScoreObj);
}
return true;
}
}
ListView is made to represent unique objects, so its items need to be UObject, that’s the way the list view class is made.
That’s because adding/removing/looking up the widget for an item needs to be very fast. An object pointer is just a memory address, so it’s fast to find an item, and you can be sure they’re unique (your list won’t accidentally show two widget for the same object). Structs on the other hand, are any arbitrary data, which can be very long (depends on what they contain). So unless you make a hashing algorithm, it’s very expensive to look up if a struct is already in the list.
So for your needs, you can use objects instead of structs to show high scores. For example, objects for each player, since the players are probably already objects. The widget can then cast to the player class when on item object set, and take the high score variable of the player to show it.
If you want to use structs though, you can create a custom widget to show the high scores. To make a vertical list, just make a VerticalBox in your parent widget and a number of widgets for each item in your list, using the create widget from class node (or NewObject in cpp). Then, add your widgets as children of vertical box using the add child to vertical box function.
I'm trying to declare a vector containing user objects in the header file, but I'm unsure of how to use the setter and getter functions to push values objects back to the vector or call them again.
class userbase
{
public:
userbase();
virtual ~userbase();
//FUNCTION DECLARATIONS
void record_User(user);
void setUserVector(vector<user> const &newUser) {
//userbase_V = newUser;
userbase_V.push_back(newUser);
}
vector<user> const &getUservector() const {
return userbase_V;
}
protected:
private:
vector <user> userbase_V;
};
Getters/setters are quite often misunderstood. The aim of using such functions is encapsulation which means restricting access to your data or exposing certain functions.
The reason why we don't make private members public in the first place is because there are some operations that we don't want users of our class to perform.
Consider the following class:
class userbase
{
public:
vector<user> users;
};
Let's say the goal of the userbase class is to manage a loyal, unwavering list of followers of an application. And since users is a public member, we can do whatever we want with it:
class company
{
public:
void massacre()
{
m_userbase.users.clear(); // Aaaaahhh!!!
}
private:
userbase m_userbase;
};
What? Where did all our loyal, unwavering followers go? We can't just remove our users!
The company class has access to all of std::vector's functionality on m_userbase.users. But really, from userbase's point of view, we don't want the outside to access particular functions (in this case, clear() or erase()). We want to restrict what operations can be performed (modifiers) and what attributes can retrieved (accessors). That is, we want to encapsulate the users vector.
Making userbase a private member is the first step:
class userbase
{
private:
vector<user> users;
};
Now let's add some naive "encapsulation" to see if it solves our problem. (This is where a lot of misunderstanding stems from.)
Here's our new class:
class userbase
{
public:
void setUsers(vector<user> const& newUsers) {
users = newUsers;
}
vector<user> const& getUsers() const {
return users;
}
private:
vector<user> users;
}
Can the company still clear the users vector directly? Yes.
class company
{
public:
void massacre()
{
auto users = m_userbase.getUsers();
users.clear();
m_userbase.setUsers(users); // Aaaaahhh!!!
// or simply create a new vector with no data
m_userbase.setUsers(std::vector<user>{}); // Aaaaahhh!!!
}
private:
userbase m_userbase;
};
So simply providing getters/setters doesn't solve the issue.
The common approach is to instead approach it the other way around. Instead of asking "What don't I want the outside to do?", ask "What do I want to allow the outside to do?". This way, you can figure what sort of functionality to expose. This is part of designing a good API.
Maybe our API wants to be able to: add a user, get a user's name, and count the number of users. Then we would design a class like this:
class userbase
{
public:
/// modifiers:
// Add a user to the userbase.
void addUser(User const& user);
/// accessors:
// Returns the user's name given its index.
string getUserName(size_t index) const;
// Returns the number of users belonging to this userbase.
size_t numberOfUsers() const;
private:
vector<user> m_users;
};
The takeaway is: it's up to you to decide what "the outside" can or can't do with its members. You'll need to spend more time thinking and less time writing code, but this is normal.
Further reading:
Why use getter and setters? (A good read even though it's tagged with Java.)
So far this is the most awkward thing I've come about. I have it set for integers to mark how many potions, keys, a player has, but I'm not sure exactly how I can get random items, like rocks, CPU (in the case of Dunnet), stick, shovel, etc.
I don't want to have to figure out every item in the game and assign it a variable. There has to be an easier way. I thought of using two arrays, one a string and one an int, to do the job - but this wont work for a variety of reasons one being I can't do string stringname[10], I see problems associating the two, and... the list goes on, I'm sure it just wont work that way.
Everything else is a class btw, I don't like using structs (but this is going to be used throughout the code, and accessed everywhere), so far my code is:
struct Inventory{
int Keys;
int Potions;
int getinventory() const { return Keys, Potions; }
void addkey(int amt){ Keys += amt; }
void addpotion(int amt){ Potions += amt; }
void usepotion(){Potions -= 1;}
void usekey()
{
if (Keys >> 0)
{
Keys -= 1;
}
else if (Keys << 1)
{
cout << "You do not have a key!" << endl;
}
}
};
I'm definitely still working on the getinventory(), because well, I'm not sure what I'm doing with this code, or even if I'm using it. is the only way I'm going to get this to work, to define EACH variable as I create it in the game and add it in?
I was going to handle weapons and monsters this way... but it just sucks not having a dynamic system for an inventory. I'd like to focus on parsing user input and not have to go back into the header where my main classes are consistently... plus I haven't even fully written the story yet, so I don't know whats happening...
The way this is addressed in LPMuds (and similar) is to create a generic object template. The generic template would have things like a short description, long description, define weight, value, etc.
Specific object types then inherit this class. For example, a potion is an object with all of those attributes but it also has additional actions (functions) that can be taken and possibly different attributes... Taste and color, for example.
Weapons can inherit from that general class, defining things like damage and hit percentage as a generalized notion. A sword can then inherit this weapon (that inherits the generic object) and can be further refined.
In this way, you simply need your inventory to be able to handle a generic object. The objects themselves may define additional attributes and actions. This also means that you don't need to predefine every single object as its own unique variable.
What about creating a structure like this:
struct InventoryItem
{
enum { Key, Potion, Rock, Stick, Shovel } type_;
unsigned int num_;
}
and then have Inventory contain something like a std::vector of InventoryItem.
I have an assignment to make Information system about resorts in a country, be able to read/write data for the resorts from/to file and modifying it.
class CTоurist{
string m_StrName;
string m_StrCountry;
int m_iAge;
public:
//constructors, mutators, accessors overloading operator <<,>>
};
I don't have problem writing this class. And here I have class which contains as member variable vector of the first class's objects
class CHotel
{
string m_strHotelName;
int m_iNumberOfBets;
double m_dAveragePrice; //average price per bet in the hotel
vector <CTourist> m_vecTourists; //vector of tourists rested in the hotel
public:
.....
};
And one more class Resort containing as member variable vector of the second class's objects
class CResort
{
string m_ResortName;
unsigned m_Height;
vector<CHotel*> m_Hotels;
public:
.....
};
So here is the problem. I'm not sure how to write the accessor,mutator and constructors for that vector variable so I can use them property. Thank you for checking and if someone could help me figure out these functions I'll be really grateful!
if i understand correctly you want to know the best way to get your hotels from cResort.
i would recommend
cHotel* GetHotelByName(std::string& a_sName)
{
for(int i = 0; i < m_Hotels.size(); ++i)
{
if(m_Hotel[i].GetName() == a_sName)
return m_Hotel[i]
}
return nullptr; // if non found return return null
}
and add a GetName function to your hotel class which returns a string of its name.
this also allows you to SetName etc.
1) Accessor, mutator: There are plenty of options.
You can create another class like CTouristList (and CHotelList respectively), that wraps the vector, have it referenced from the CHotel class (accessor methods like CTouristList& CHotel::GetTouristList() and const CTouristList& CHotel::GetTouristList() const) and implement methods like CTouristList::Add, CTouristList::Remove, CTouristList::Get, etc.
Or you can add methods like CHotel::AddTourist() directly on the CHotel class.
2) Constructor. Nothing needed in constructor. But for vector<CHotel*> you may need destructor in CResort to explicitly free the CHotel instances. Though not sure why you want to use pointers to CHotel.
You can put the accessor and mutator functions in CTourist just like you would if they were not being stored in a Vector.
To utilize them once they are in CHotel you could add a function in CHotel that returns a pointer to a CTourist.
// Access a CTourist
Hotel.getTourist(1)->setName("Tourist name");
Adding a method that returns the number of tourist that visited a hotel would make it easier to loop through them.
for(int i = o; i < Hotel.touristCount(); ++i)
{
// Do something useful
std:: cout << "Hello " << Hotel.getTourist(i)->getName();
}
In that case your CHotel::touristCount() would be a wrapper around the vector<>.size();
If you do not want code outside of CHotel to have direct access to a CTourist object then create wrapper functions in CHotel that do what you would want to do externally.
i.e.
std::cout << Hotel.getTouristName(1);
instead of
std::cout << Hotel.getTourist(1)->getName();
I do not understand how to implement the following code to allow the function to write into the existing array.
void Project::addStaff(const Staff&)
{
//add employees into staff array
}
having (const Staff&) as parameters is new to me as it does not create an object anyways. I can not change it because it is to be used as is to implement the program correctly. the Staff constructor is as follows
Staff::Staff (std::string lname, std::string fname)
: theLname(lname), theFname(fname)
{}
Is there a way to write the variable for staff so I can access the needed values to place into the array? Any help would be greatly appreciated!
Your Project class may have a std::vector data member, and you can use vector.push_back() method to add new Staff instances in the array:
// Inside Project class:
std::vector<Staff> m_staffPersons;
void Project::addStaff(const Staff& newStaff)
{
// Add employees into staff array
m_staffPersons.push_back(newStaff);
}
I would define std::vector<Staff> representing list of employees as a member of this Project class:
class Project
{
public:
void addStaff(const Staff&);
vector<Staff> employees;
}
Then your addStaff method could look like this:
void Project::addStaff(const Staff& newEmployee)
{
employees.push_back(newEmployee);
}
But I would definitely rename class Staff since it doesn't say much about itself. Employee would be much better name for this class.