and I've hit my first wall on my coding project/assignment.
I'm to implement functionality into code that's been done to some stage, and I cannot alter the given code so I have to work around the given structure.
The code, in a nutshell, reads family relations from a text file and populates database with the family relation data and later on allows user to print out information he wants to access.
What I'm having trouble with is understanding how I can and how I have to utilize a struct given to me in the assignment. The struct is
struct Person
{
std::string id_ = NO_ID;
int height_ = NO_HEIGHT;
std::vector<Person*> parents_{nullptr, nullptr};
std::vector<Person*> children_;
};
and I'm using it at least in the initialization phase of the data structure.
I start by calling the process in main.cpp with
database->addRelation(it->child_, it->parents_, std::cout);
In the naming/height adding phase I'd simply do it with
MyPerson.id_ = id;
MyPerson.height_ = height;
where MyPerson is defined by Person MyPerson;
but as far as I can tell, I have to somehow access the object pointers to be able to populate the vectors for when I want to add children/parents to the person.
The class functions that are called when initializing person's name, height and family relations are these two:
void Familytree::addNewPerson(const string &id, const int &height, ostream &output)
{
MyPerson.id_ = id;
MyPerson.height_ = height;
}
void Familytree::addRelation(const string &child,
const std::vector<string>
&parents, ostream &output)
{
}
The addRelation fuction is what I'm having a hard time getting to work. Simply appending the strings to it won't work since it expects Person* -objects, which are, as far as I can tell, just pointers to the other Persons, but I'm not sure how I can access them.
Also, let me know if anything here is excessive or if I'm missing anything crucial, I'll edit it to the best of my ability
Editing with additional information:
The only things I've added myself that can be seen here is
Person MyPerson;
and the contents of the class function addNewPerson. The other snippets I can not change in any shape or form.
Edit#2
Current progress, debatable whether I'm closer or further from the goal
My persons map is using Personmap = std::map<std::string, Person >;
and I'm using it in addNewPerson with
persons_[id] = id;
persons_[id] = height;
, but I'm still randomly trying different things to try and make it work for the next phase where I need to somehow add the objects to the vectors.
The biggest problem I have is the fact that I do now know how to play around the difference of *Person and Person
Related
I'm currently designing classes that should represent a chaotic storage system.
Lets say we have slots in rows and columns with certain properties.
So the slots have different restrictions in min/max height, width, length, weight and some more that come from a parameter file.
Also the Slots have a max total weight that must be checked before a new parcel gets added to that slot. And also the max weight that a row of slots can hold is lower than the sum of the max weights of the single slots. So for example each individual slot might be able to hold 50kg but the row of 10 slots must not exceed 200kg, so it is not allowed to fill every slot by 100%. The same is true for the Columns where the maximum weight is lower than the sum of the individual weights of the single rows. The row_id and column_id are atrificial numbers for adressing the slot in the physical system with barcodes or whatever that get read for positioning.
As all this parameters do not change over the lifetime of the program, my intention was to design the classes in a way that this properties are readable by getter functions but there should not be any setter functions (maybe not even private ones) in the object o the values cannot be changed by accident.
There is one class/function that reads the config-file and generates the data structure for the rows and columns with the slots. This function should be able to read the config and create objects for every column holding a row of slots and pass all the values from the config down to the slot.
Later when the program is running I also need some way to search for the best matching slot to add the next parcel or for searching parcels and unload them in a certain sequence.
So the (simplfied) basic structure of the classes would be like this:
Class Parcel {
int width;
int height;
int length;
int weight;
}
Class Slot {
vector<Parcel> parcel;
int min_width;
int max_width;
int min_height;
int max_height;
int min_length;
int max_length;
int max_total_weight;
int act_total_weight;
int total_length;
int free_length;
}
Class Row {
vector<Slot> slot;
int row_id;
int max_total_weight;
int act_total_weight;
}
Class Column {
vector<Row> row;
int column_id;
int max_total_weight;
int act_total_weight;
}
Class Storage {
vector<Column> column;
}
So here are my thoughts about how to initialize the data structure:
First possibility would be to pass all the properties in the constructor(s) of the classes, but then the constructors has some huge parameter lists specially for the Slot class that has a lot of properties.
Second thing that came to my mind (and currently my fafourite way to go) is to use config-data-structures that hold all the parameters. This parameter-objects get filled by the config-function and passed to the constructor when initializing the class. Then it also may be useful to use the parameter class as such and not having all the parameters defined in the storage class once more.
Third way is to use private setter and public getter and make the config class friends with the data structure classes to be able to access the setter functions (but i would prefer to have no setters at all in the final storage structure classes.
Fourth way that i was thinking off, was to derive child classes from the structure classes that hold the setter functions (and also some other logic needed for creating the data structure) so the child has no own variables but only additional functions. So the child class is used to fill the properties but the base class gets added to the data structure vector.
I also want to use Factory pattern to initialize the data structure because the objects have often similar or only slightly different properties. So with the second aproach after creating one row of slots I would maybe want to change the max weight of the slots in that row. Therefore I would need to change the setting in the factory and the factory then fills the parameter data structure differently and passes it to the Slot class. Or is it better to pass the data structure to the factory directly and the factory assigns it but then i think this is not what the factory pattern is meant to be.
I don't know if this is a good aproach or which of the above is best practice.
Or am I missing something and there is a way more convenient solution or this?
Thank you (and sorry if the question is maybe not the way it should be)
When constructing your classes as you describe it you can have a look at the creational design patterns.
Your second proposed solution is almost a builder design pattern. This will help you to construct the Slot e.g. piecewise.
As an example:
#include <iostream>
class Slot {
public:
int GetMinWidth() const { return min_width_; };
int GetMaxWidth() const { return max_width_; };
// Builder class
class SlotBuilder {
public:
SlotBuilder& SetMinWidth(int min_width) {
min_width_ = min_width;
return *this;
}
SlotBuilder& SetMaxWidth(int max_width) {
max_width_ = max_width;
return *this;
}
Slot Build() {
return Slot(min_width_, max_width_);
}
private:
int min_width_{/* you can add default value here*/};
int max_width_{/* you can add default value here*/};
};
// This is optional, but creates a neat interface
static SlotBuilder Create() {
static SlotBuilder slot_builder;
return slot_builder;
}
private:
// Make constructor private to restrict access and force the use of the builder
Slot(int min_width, int max_width) : min_width_(min_width), max_width_(max_width) {}
const int min_width_;
const int max_width_;
// .
// .
// Continue with your const attributes
};
int main() {
// Create the slot with the builder
Slot slot = Slot::Create()
.SetMinWidth(10)
.SetMaxWidth(20)
.Build();
std::cout << slot.GetMinWidth() << ", " << slot.GetMaxWidth();
return 0;
}
You can see the example working here
For having different types that are almost the same a Prototype pattern could work if you want to "clone" a class or in your case a Factory pattern could do the job.
There is never an ideal solution or that one pattern that solves it all, so I can't give you a definitive answer, but here are some collected thoughts:
Default values
Primitive types like int don't have a default value, so make sure you give them one explicitly:
struct Parcel {
int width{};
int height = 0;
int length = {};
int weight{};
}
All those different versions above are equivalent, but you really should use one of them. Otherwise you will probably run into UB down the line.
Const correctness
One thing that I love about C++ and that I dearly miss in languages like C# is const correctness. If you want an object to be immutable, declare it as const. To prevent changes to your objects, either instantiate the object as a const:
const Parcel x;
x.width = 10; // compiler error
or make the members of your classes const:
struct Parcel {
const int width{};
const int height{};
const int length{};
const int weight{};
};
Parcel x;
x.width = 10; // compiler error
Aggregate initialization
If you keep your types simple enough you can initialize the class members with curly braces directly:
const Parcel x { 1, 2, 3, 4 };
In C++ 20, you can also name the members, so this code is equivalent to the line above:
const Parcel x { .width = 1, .height = 2, .length = 3, .weight = 4 };
Note that this can bite you later though if you have to deal with ABI stability and versioning. In that case you are better off using getter and setter functions, because that allows you to still change the data layout of your members.
I have to think about design patterns a bit more. I'll update this post if something useful comes out of it.
I have a basic inventory system in UE4 using a TArray of pointers to my custom Item class. It works fine in individual levels, but when I open a new level, the inventory disappears. I've looked at multiple tutorials and posts about this issue and tried various solutions including migrating my inventory array to the Game Instance, and creating a SaveGame class that holds a copy of the array that saves before and loads after opening a level
After all these, inventory still disappears. My code has changed a lot so it's probably not that helpful but here are some snippets of my current solution.
Declaration in character header
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<AItem*> Inventory_Space;
Declaration in SaveGame
UPROPERTY(SaveGame)
TArray<AItem*> Inventory_Save;
Save and load functions in character implementation
void ABatteryManPlayer::SaveInventory()
{
UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
(UGameplayStatics::CreateSaveGameObject(UBatteryMan_SaveGame::StaticClass()));
for (int i = 0; i < INVENTORY_SIZE; i++) {
SaveInstance->Inventory_Save[i] = Inventory_Space[i];
}
UGameplayStatics::SaveGameToSlot(SaveInstance, TEXT("Slot0"), 0);
}
void ABatteryManPlayer::LoadInventory()
{
UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
(UGameplayStatics::CreateSaveGameObject(UBatteryMan_SaveGame::StaticClass()));
UBatteryMan_SaveGame* SaveInstance = Cast<UBatteryMan_SaveGame>
(UGameplayStatics::LoadGameFromSlot("Slot0",0));
for (int i = 0; i < INVENTORY_SIZE; i++) {
Inventory_Space[i] = SaveInstance->Inventory_Save[i];
}
}
Saving after game timer goes to 0 (character implementation)
CurrentTime--;
if (CurrentTime == 0) {
SaveInventory();
Instance->Levels_Complete++;
if (Instance->Levels_Complete < Instance->NUM_LEVELS) {
FName Level_Name = FName(TEXT("Level_" + FString::FromInt(++Instance->Levels_Complete)));
UGameplayStatics::OpenLevel(this, Level_Name, false);
}
Loading back into player inventory in GameMode
void ABatteryMan_GameMode::BeginPlay() {
Super::BeginPlay();
ABatteryManPlayer* Player = Cast<ABatteryManPlayer>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
Player->LoadInventory();
FTimerHandle UnusedHandle;
GetWorldTimerManager().SetTimer(
UnusedHandle, this, &ABatteryMan_GameMode::SpawnPlayerRecharge, FMath::RandRange(2,5), true);
}
I believe that you may have found out why the issue is occurring from our discussion in the comments, but I will try to finish our discussion with this answer. The problem is that you are trying to save an array of pointers to actors in a map. However, the actors in the map get destroyed once you call UGameplayStatics::OpenLevel in order to change the map. As a result, the pointers in that array end up pointing to garbage data, which is why your game is crashing.
Now, there are many ways to go about this, but you're ultimately going to have to save information about the actors and respawn them. What I have found on Unreal Engine forums is that a common approach is to create a custom struct of type FArchive for information about these actors, in your case about instances of AItem. For example, a struct called AItemInfo which will store info such as the actor's class, the actor's transform, the actor's name, etc., as well as a TArray member representing a serialized bytestream of other data from an actor (AItem). Then, serialize the actor into that struct's TArray member variable using a FMemoryWriter object. Note that typically you wouldn't serialize all the information about actor, only specific variables/properties marked with the SaveGame property specifier when you set the ArIsSaveGame variable in your struct to true. After doing that for each AItem instance you want to keep track of, you can store each instance of this AItemInfo struct in an array defined in your custom USaveGame class. In your case, it's UBatteryMan_SaveGame. Then, you can call UGameplayStatics::SaveGameToSlot on your UBatteryMan_SaveGame instance that contains the array of information structs. When you load that UBatteryMan_SaveGame instance, you can deserialize the array/sequence of bytes in each AItemInfo struct in the array with a FMemoryReader object in order to get the actor information in addition to the other stuff already in the struct and use all of that information to recreate each actor you need from the original map.
Here are a couple of good links that can help you get started:
https://answers.unrealengine.com/questions/35618/savingloading-an-array-of-objects.html
https://www.ue4community.wiki/legacy/savegame-pointers-and-structs-8wlg0qms
Another approach to saving game data
I'm reading through Martin Fowler's PoEAA right now on object-relational structural patterns. As a project to do while learning them, I thought I'd build a mini eCommerce system in C++. I'm having trouble figuring out how to return the objects from the mapper.
I have a Product base class, which has derived classes Hat and Shirt. Products have a type member to identify which derived class they are. I also have a ProductMapper class, with derived classes HatMapper and ShirtMapper, all of which implement a bunch of finder methods which let me try and retrieve certain hats and shirts.
class Product
{
unsigned long long int id;
std::string name;
unsigned int type;
};
// Derived classes don't necessarily have the same members.
class Hat : public Product
{
unsigned char fitted;
unsigned char color;
unsigned char style;
};
class Shirt : public Product
{
unsigned char size;
};
In the logic part of my application where I'd instantiate these mappers and retrieve products is where I'm having trouble. I can instantiate a HatMapper and pull back Hat objects without any problem, same with a ShirtMapper and Shirt objects. The patterns work great in these cases (in particular I'm using class table inheritance, i.e. one product table with product data, one table for hats with hat-specific data, and one table for shirts with shirt-specific data).
My problem is, what do I do if I want to retrieve all products, both hats and shirts? I can instantiate a ProductMapper and fetch all of the product data, but that seems like the wrong approach since I'd have to loop through all the Products I retrieve and build up Hats and Shirts based on their type in my logic portion of the program. Additionally, I'd have to modify any code that handles the situation this way when I add new product types. Seems bad.
The Fowler book has examples of the mappers with the base mapper using the derived mappers which seems completely wrong to me (have to modify the base mapper every time I add a new product, not great). Here's a quick example of how it's done there:
class ProductMapper
{
unsigned long long int productId;
unsigned long long int productType;
HatMapper * hm;
ShirtMapper * sm;
Product * FindById(unsigned long long int id)
{
// Query database for data.
if (this->productType == PRODUCT_TYPE_HAT)
{
return hm->FindById(id); // Hat object.
}
else if (this->productType == PRODUCT_TYPE_SHIRT)
{
return sm->FindById(id); // Shirt object.
}
return NULL;
}
};
Here's how I'd use this in the logic part of my program. Examples of this aren't provided in the book:
ProductMapper * pm = new ProductMapper();
Product * p = pm->FindById(1); // It's a Product, but a Hat or Shirt?
// Have to check type since a Product was returned.
switch (p->type)
{
case PRODUCT_TYPE_HAT:
{
Hat * h = (Hat) p;
break;
}
// Etc. Modify this every time a new product type is added or removed.
}
This will introduce circular dependencies. Additionally, assuming I somehow eliminate the circular dependencies, the result of the HatMapper and ShirtMapper classes are Hat objects and Shirt objects. Thus when I return from the ProductMapper, I'll be downcasting, so I'd have to again manipulate the result in my logic, which again introduces the issue of modifying code when I introduce new product types.
I'm at a loss for what to do. In a perfect world, I'd like to have a Product class and a ProductMapper class, both of which I can extend quickly, introducing new product types without having to modify existing code (at least too much).
I would like to be able to use these patterns from PoEAA, they do seem nice and useful, but I'm not sure if it's just something I can't do in C++ or I'm missing something that's preventing me from doing it. Alternative patterns and approaches are also really welcomed.
It feels like the Type Object pattern could help in this case, I know the link is about game programming but it is sufficient to apply the pattern to other domains.
The problem right now is that if you want to add products you have to add several classes, which can become hard to maintain as you noticed.
Edit: Maybe you could use something like that (code is C++11 to simplify the example):
class ProductProperty
{
typedef std::map<std::string, unsigned char> PropertyMap;
PropertyMap properties;
public:
ProductProperty(std::initializer_list<PropertyMap::value_type> il):
properties(il)
{}
// Use of at() is intended to only deal with the defined properties
const PropertyMap::value_type::second_type&
get(const PropertyMap::value_type::first_type& prop) const
{
return properties.at(prop);
}
PropertyMap::value_type::second_type&
get(const PropertyMap::value_type::first_type& prop)
{
return properties.at(prop);
}
};
// Some helpers to illustrate
std::shared_ptr<ProductProperty> makeHatProperty()
{
return std::make_shared<ProductProperty>(
ProductProperty{
{"fitted", ***whatever**},
{"color", ***whatever**},
{"style", ***whatever**}
});
}
std::shared_ptr<ProductProperty> makeShirtProperty()
{
return std::make_shared<ProductProperty>(
ProductProperty{{"size", ***whatever**}}
);
}
class Product
{
unsigned long long int id;
std::string name;
unsigned int type;
std::shared_ptr<ProductProperty> properties;
public:
Product(std::shared_ptr<ProductProperty> props):
properties(props)
{}
// Whatever function you need to get/set/check properties
};
I am making an airline reservation software and I don't know much about the Visual C++. I am using the simple compiler "TCWIN45". In my program I wish to use file handling and I am succeed to save all the inputs in text file. i need to add search option and modification option. if user choose search and Enter the name then how can I access specific number of lines. because my files contains the record of multiple passengers but I want to show the only one's data. same is the case for modification. I want to access specific location or line and also to overwrite it. please suggest me the most simplest way.
This is my code to save all the record in one text file:
ofstream thefile("ID.txt" , ios::app);
thefile<<"\n\nDay : "<<p1[i].day<<"\nFlight Date : "<<p1[i].date<<"\nFlight Type : "<<p1[i].type<<"\nReturn Date : "<<p1[i].rdate<<"\nDeparture Place : "<<p1[i].from<<"\nDestination : "<<p1[i].to<<"\nClass Type : "<<p1[i].clas<<"\nTime of Flight : "<<p1[i].time<<"\nTitle : "<<p1[i].prefix<<"\nFirst Name : "<<p1[i].fname<<"\nLast Name : "<<p1[i].lname<<"\nDate of Birth : "<<p1[i].dob<<"\nPassport Number : "<<p1[i].ppt_no<<"\nExpiry Date : "<<p1[i].edate<<"\n Contact Number : "<<p1[i].cont<<"\nMeal Type : "<<p1[i].meal<<"\n\n------------------------------";
Ali, this can be done in a flat file if you really want to not use a database. The trick, is to either: 1.) have all records the same size OR 2.) have a "record header" that provides "enough" information to be able to unserialize the record from the hard disk. If you store different kinds of records, "enough" information could be size of the record or a record type for RTTI purposes. I find it useful to also store an ID for each record so that I can store an index table for record offsets.
If you records have varying sizes, then your record's serialization functions have to be able to handle this. In fact, it is trivial to do this.
The index table is a table of file offsets.
typedef uint16_t record_id;
typedef long offset_t;
offset_t indices[ MAX_RECORDS ];
typedef struct _record {
uint16_t type;
uint16_t id;
offset_t next;
offset_t prev;
} record;
typedef struct _header {
uint32_t count;
offset_t first_record;
offset_t deleted_record;
} header;
So to find the position of the record, you find the offset into the file, which is indices[ record_id ]. Adding a record is like adding a node to a linked list, but the nodes are in the file.
Deleting records is a little tricky. You have to use "lazy delete" to delete records and later these deleted records get reused. You can even write a shrink function that will remove all deleted records from the file to free up unused space.
The limitations of this technique is that you can only search by record id. If you have other information, you will need to generate additional data structures to support this.
I have code available that does this in C if you would like a working example. However, doing this from scratch is feasible but NOT WORTH THE EFFORT. Just use a database like Sqlite or MySQL--it will save time!
Example Code
flat-db.c
flat-db.h
test-flat-db.c
From your comments to other answers, it does not seem like the best way for you to do this is to store the data in a text file at all. You will probably want a Reservation class that contains all of the information for the reservation. Then, use some kind of Collection to store all of the reservations. Writing to a text file just adds a huge amount of unnecessary difficulty.
Something like this:
class Reservation
{
std::string day;
std::string date;
std::string flightType;
std::string meal;
/* ... */
};
It would be even better if you made separate classes for each one of the class members (like a Day class, a FlightType class, etc.).
You would then use some kind of Map to access a particular reservation and change its members.
You'll probably want to define a reservation class that represents a single reservation, and a data class, that holds all your data, as a vector of reservations. The data class will want to have a member function that takes a std::ostream by reference, and saves the reservations to a text file, (easiest is one variable per line). It will also want a member function that takes a std::istream by reference and reads in the data from the text file.
The main part of your program would (I'm making TONS of assumptions here) load the file into the data class with the std::istream member function, and asks the user for some sort of ID. You then call a member function of data that checks all of the elements in datas vector until it finds the matching ID (by reference), and lets the user change some members. Then it calls the std::ostream member function again to save the changes.
Streams are handled like this. In this sample, I do not use the data class or a vector, since this question looks suspiciously like homework, but this shows the tricky parts of file handling.
#include <string>
#include <iostream>
#include <fstream>
class Reservation {
std::string ID;
std::string date;
public:
//default constructor
Reservation()
{}
//helpful constructor
Reservation(std::string _id, std::string _date)
:ID(_id), date(_date)
{}
//copy constructor
Reservation(const Reservation& b)
:ID(b.ID), date(b.date)
{}
//move constructor
Reservation(Reservation&& b)
:ID(std::move(b.ID)), date(std::move(b.date))
{}
//destructor
~Reservation()
{}
//assignment operator
Reservation& operator=(const Reservation& b)
{
ID = b.ID;
date = b.date;
return *this;
}
//move operator
Reservation& operator=(Reservation&& b)
{
ID = std::move(b.ID);
date = std::move(b.date);
return *this;
}
//save
std::ostream& save(std::ostream& file) {
file << ID << '\n';
file << date << '\n';
return file; //be in the habit of returning file by reference
}
//load
std::istream& load(std::istream& file) {
std::getline(file, ID);
std::getline(file, date);
return file; //be in the habit of returning file by reference
}
};
int main() {
Reservation reserve; //create a Reservation to play with
{ //load the reservation from loadfile
std::ifstream loadfile("myfile.txt");
reserve.load(loadfile);
}
//display the reservation
reserve.save(cout);
{ //save the reservation to a different file
std::ofstream savefile("myfile2.txt");
reserve.save(savefile);
}
return 0;
}
Is there any efficient way in C++ of generating an ID unique to the class, not to the instance? I'm looking for something of this level of simplicity (this generates an ID for every instance, not for every class type):
MyClass::MyClass()
{
static unsigned int i = 0;
id_ = i++;
}
Edit: Why I want unique IDs.
I'm writing a game. All entities in my game will have different states they can be in (walking left, jumping, standing, etc); these states are defined in classes. Each state needs to have its own ID so I can identify it.
You can try this, but it's not-deterministic.
int id_count = 0;
template <typename T>
int get_id()
{
static int id = id_count++;
return id;
}
Then just use:
get_id<int>(); // etc.
Of course, this isn't thread safe.
Again, it's not deterministic: the IDs are generated the first time you call the function for each type. So, if on one run you call get_id<int>() before get_id<float>() then on another run you call them the other way round then they'll have different IDs. However, they will always be unique for each type in a single run.
Basically you are asking for a custom rolled RTTI solution, that you can selectively apply to classes.
This can start from very crude preprocessor stuff like :
#define DECLARE_RTTI_CLASS(a) class a { \
inline const char * class_id() { return #a };
.. to a more sophisticated solutions that track inheritance etc, essentially partially duplicating compiler RTTI functionality. For an example, see Game Programming Gems #2, Dynamic Type Information
Previous discussions on gamedev on the same subject are also worth reading
Use your MyClass as a primitive, and incorporate a static instance of one into each class you want to ID.
class MyOtherClass1 {
static MyClass id;
};
class MyOtherClass2 {
static MyClass id;
};
[etc.]