Lets say I have the following class:
static int counter = 0;
class Account {
public:
int ID;
int favNumber;
Account(int favNum) {
this->ID = ++counter;
this->favNumber = favNum;
}
};
Account user1(4);
Account user2(9);
Now both accounts user1 and user2 have different ID that is unique. Is there any way by knowing the ID of the account get the field of the object like "favNumber", if so how should it be implemented?
Something like getFieldById(int ID)
You may use std::map to do this :
#include <map>
class Account {
// Make attributes private. It is a better practice
int ID;
int favNumber;
static int s_Counter;
//^^^^^^^^^^^^^^^^^^^^^ It is better to move it as a static private member of Account
public:
Account(int favNum) {
this->ID = ++s_Counter;
this->favNumber = favNum;
}
// GETTERS
int GetFavNumber() const { return favNumber; }
int GetID() const { return ID; }
};
int Account::s_Counter = 0;
// ^^^^^^^^^^^^^^^^^^^^^^^^ Don't forget to initialize it
Account user1(4);
Account user2(9);
std::map<int, Account*> accounts;
accounts[user1.GetID()] = &user1;
accounts[user2.GetID()] = &user2;
// To get a favNum with some id :
accounts[id]->GetFavNumber();
But with this technique, be sure that the pointers are still valid ! If not, you could have bad surprises ...
What we have done in this previous code ?
We passed the attributs in private (better practice).
We created Getters to access them.
We passed the counter static variable as a static private member of Account.
We used std::map to have a listing of the accounts created and the keys are the IDs of the Accounts.
You can use
std::map<int, Account*>
to store a pointer to the accounts by their id. It's up to you to make sure the pointers remain valid. Alternatively, you could use
std::map<int, Account>
and let the map look after your accounts for you.
you can create a list and for each time you pass the constructor add the item to the list. then when a request get to your getFieldById search your list.
the list will have to be in a place you can search in and only be initiate once
You would need to central place to store all the objects that are going to be created and then search for the id there.
You could store them as
Plain old array
Search the entire list for your object of ID and then return the field
ID indexed array
array[ID] is the object you need, return the field
Hash(std::map) from ID to object
Similar syntax as ID indexed array but is a hash table lookup
Each have their pros and cons in simplicity, speed of search, memory used etc.
You could also store object pointers in the above.
To automate things, you can make the above list a private static member of your Account class, and add to it in the constructor.
Related
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.)
Absolute newbie to c++ (and oop) as well.
Just wanted to ask how to return an object from a list (if it exists), by passing a single id to a getter.
My code is as follows:
class Customer
{
private:
unsigned int custNo;
std::string name;
std::string address;
/* .. */
}
class Store
{
private:
std::string storeName;
std::list<Customer *> customerBase;
std::list<Product *> productStock;
std::list<Sale*> sales;
public:
Store(std::string storeName); // constructor
std::string getStoreName();
Customer & getCustomer(unsigned int custId); //METHOD IN QUESTION
/*..*/
// Constructor
Customer::Customer(std::string name, std::string address)
{
//ctor
}
//
Customer & Store::getCustomer(unsigned int custId){
}
I know this might be a farily basic question. Still I would very much appreciate the help. Thanks in advance!
Just wanted to ask how to return an object from a list (if it exists), by passing a single id to a getter.
Pointer is the first thing that you should think when you see "if it exists". This is because the only representation of an object in C++ that can be optional is a pointer. Values and references must always be present. Therefore, the return type of your function should be Customer*, not Customer&:
Customer* Store::getCustomer(unsigned int custId){
...
}
If you need fast retrieval by an id, use a map<int,Customer*> or unordered_map<int,Customer*>. You could do it with a list, too, but the search would be linear (i.e. you would go through the entire list in the worst case).
Speaking of pointers, if you must store pointers to Customer objects, assuming that the objects themselves are stored in some other container, you may be better off using shared_ptr<Customer> in both containers, to simplify resource management.
You can do this but it would be cumbersome as list is not sorted so you have to traverse the list and check each structure for matching id.
Rather you could store these in std::map with ids as their keys...OR much better unordered_map if you really care about performance.
Assuming you have getCustId() public member function in class Customer:
Customer & Store::getCustomer(unsigned int custId){
auto custIt = find_if(customerBase.begin(), customerBase.end(),
[custId](const Customer& c){ return c.getCustId() == custId });
return *custIt;
}
My teacher required us to create ID data member that's generated automatically, and once established it can’t be modified.
What is the most appropriate type?
if the answer is
static const int ID;
How can I generate it automatically while it's const?
Since the ID has to be unique, one shall make sure, that two instances never get the same ID. Also, noone outside class should interfere in generating the UID.
First, you define a static field in your class:
class Data
{
private:
static int newUID;
(...)
};
// The following shall be put in a .cpp file
int Data::newUID = 0;
Then, after each instance is created, it should take a new ID value and increment the newUID counter:
class Data
{
(...)
const int uid;
public:
Data()
: uid(newUID++)
{
}
int GetUid()
{
return uid;
}
};
Noone has access to internal newUID except the class, ID is generated automatically for each instance and you are (almost1) sure, that no two instances will have the same ID number.
1 Unless you generate a little more than 4 billion instances
Here is an example:
class SomeClass {
static int currID;
public:
const int ID;
SomeClass() :
ID(currID++) { // Initialization list used to initialize ID
}
};
And you must put this somewhere in your .cpp file:
int SomeClass::currId = 0;
This uses initialization lists to do the trick. We must do it this way for it is only in initialization lists where you can assign to a const member in an instance.
The core concept is that you must have a "global setting" to keep track of the ID that would be assigned to instances created in the future. It is currID in this example. For each instance created in your class, you assign the value of currID as the ID of that instance then increment it (currID). In this way, you get instances which have unique IDs.
create a const ID as int , initialize it in constructor initialization list like
SomeClass(): id(++staticIncrementingInt){
///other stuf here
}
Hope this helps.
You can actually call a function (rand, in this case) in the construction initialization list.
Up to you now how you can seed it.
If your teacher allows boost libs then try Boost.Uuid. An example is here. It is RFC 4122 compliant.
I have a simple Store class that contains an Inventory object and a CashRegister object. In order to sell an item, the CashRegister object needs to access the Inventory object's methods; namely, those which return a particular item's price, quantity held in storage, etc. What's the best way to give the CashRegister object access to the Inventory object's methods?
Thank you.
the CashRegister object needs to access the Inventory object's methods
Why? The CashRegister can exist and operate perfectly without an Inventory. You can have a CashRegister in a theater or a cinema, not only in a Store. This part of the logic you're talking about should be part of the store.
class Store
{
CashRegister register;
Inventory I;
void sellSomething(Item i)
{
//move logic inside the store
//not in CashRegister
int price = I.getPrice(i);
register.addCash(price);
I.removeItem(i);
}
};
One solution is to store a reference to the Inventory object in the CashRegister object, and give the reference when constructing the Store object.
class Inventory { /* ... */ };
class CashRegister
{
public:
CashRegister(Inventory &inventory)
: inventory_(inventory)
{ }
// ....
private:
Inventory &inventory_;
};
class Store
{
public:
Store()
: cashregister_(inventory_)
{ }
// ....
private:
Inventory inventory_;
CashRegister cashregister_;
};
class Inventory {
Currency price;
uint64_t quantity;
public:
Currency get_price() { return price; }
uint64_t get_quantity() { return quantity; }
};
Then your cash register can call the functions on an instance of Inventory.
But really, you should put a function on Inventory to reserve or deliver a certain number of objects if available -- a cash register does not need to know how many items are in stock, it only needs to know whether the current demand can be satisfied. For that matter, I'm not sure that an Inventory needs to know the price of an object -- if there's 10% off on Wednesday afternoons, then what business is that of the warehouse?
Give objects responsibilities, don't just use them for clumping data.
The Inventory should know how to add and remove Items. It may be that a transaction needs to take place. This assignment is a metaphor for a database.
#Luchian has the right idea but I would take it further.
You want the Inventory (database) to be able to process Transactions, in this case one which is specialised to use a cash register.
The Item should be able to represent itself to the Inventory.
Look at the ideas of Tell Don't Ask, and Write No Getters.
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.