Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
What is the best design for loading an object from a file? There are lots of possibilities, some of which are shown below.
class object
{
public:
object(const std::string& filename);
};
class object
{
public:
object();
void load_from_file(const std::string& filename);
};
class object
{
public:
static object load_from_file(const std::string& filename);
object(object&& an_object);
};
class object
{
public:
std::unique_ptr<object> load_from_file(const std::string& filename);
};
class object_loader
{
public:
std::unique_ptr<object> load_object_from_file(const std::string& filename);
};
and the list goes on...
Edit:
The design I went with was this:
class object
{
public:
object();
};
class object_loader
{
public:
void load_from_stream(object& an_object, std::istream& input_stream);
};
I would prefer 'class object_loader' which separates the IO loader from the container, allowing future implementation of different loaders (from txt, binary, xml ... file) without modifying original data container. Better testing possible. Also possible to remove IO from app, if no IO allowed (like embedded devices, etc).
What is the best design for loading an object from a file?
The best design usually is along these lines:
class object { public: object(); /* ... */ }; // object is default constructible
std::istream& operator >> (std::istream& in, object& o);
client code:
// from file:
std::ifstream fin(path);
object o;
fin >> o;
// from serialized string:
std::string contents = ".....";
std::istrigstream ssin(contents);
ssin >> o;
Edit:
Transactional implementation:
std::istream& operator >> (std::istream& in, object& o)
{
int i; std::string word; // example data required by object instance
if (in >> i >> word)
{ // read was successful for all data
o.set_index(i);
o.set_word(word);
}
return in;
}
// client code:
if(ssin >> o)
{ // read was successful
// use o here
} else {
// o is still as default-constructed
}
This approach will work the same also if the stream throws exceptions on errors.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a problem with my getters and setters in C++. I implemented a Queue, I also implememented a class Process. My queue saves processes. My class Process has two attributes: "Identifier" and "Time" and also has setters and getters. I set 80 as its Time. The problem then is that I want to modify the time to 50 and it doesn't change. I think that the problem is the Queue, but I don't know where. Heres is my fragment of code
Queue<Process> process;
Process x;
x.setIdentifier("Hi");
x.setTime(80);
process.enqueue(x);
process.getElementFront().setTime(50);
process.print();
Here is my Queue code:
class Queue{
private:
int size;
Node <L> *front;
public:
.
.
.
//front()
L getElementFront() const{
return this->front->getElement();
}
Here is my Node code:
class Node{
private:
L elem;
Node *next;
public:
.
.
.
L getElement() {
return this->elem;
}
This is my Process Class:
class Process{
private:
string identifier;
int time;
public:
Process(){
identifier = "";
time = 0;
}
string getIdentifier(){
return identifier;
}
int getTime(){
return time;
}
void setTime(int time){
this->time = time;
}
void setIdentifier(string identifier){
this->identifier = identifier;
}
friend ostream &operator<<(ostream &o, const Process &p);
};
ostream &operator<<(ostream &o, const Process &p){
o<<"Identifier: "<<p.identifier<<"\n";
o<<"Time:"<<p.time<<"\n";
return o;
}
The output of the first code is: Time = 80. I should be Time = 50, but time wasn't modified.
I believe your function "getElementFront" returns a copy of your element, So your queue will never be affected. You can write a function like "setElementFront(int)" to affect the element directly or something like this.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I have this class to store fixed known data. Each object should have its own unique id in such way that, when the user calls Belt belt(1), an object with the correct values of name, perimeter, nOfPoints is created. Is there any better way to define these other parameters without a switch-case? Should I design this in another way? What are the disadvantages of such implementation?
class Belt {
private:
int _id;
std::string _name;
int _perimeter;
int _nOfPoints;
public:
Belt(int id){
_id = id;
switch (id)
{
case 1:
_name = "NEO";
_perimeter = 100;
_nOfPoints = 10;
break;
case 2:
_name = "PED";
_perimeter = 200;
_nOfPoints = 12;
break;
case 3:
_name = "ADT";
_perimeter = 400;
_nOfPoints = 20;
break;
}
}
};
Is there any better way to define these other parameters without a switch-case?
You could use a private static map to hold your prototypes:
class Belt {
private:
static const std:map<int,Belt> prototypes;
int _id;
std::string _name;
int _perimeter;
int _nOfPoints;
Belt(int id, const std::string name, int perimeter, int nOfPoints)
: _id(id), _name(name), _perimeter(perimeter), _nOfPoints(nOfPoints) {}
public:
Belt(int id) {
_id = id;
_name = prototypes[_id]._name;
_perimeter= prototypes[_id]._perimeter;
_nOfPoints= prototypes[_id]._nOfPoints;
// Or simpler instead of the lines above:
// *this = prototypes[id];
}
};
const std:map<int,Belt> Belt::prototypes = {
{ 1 , Belt(1,"NEO",100,10) }
, { 2 , Belt(2,"PED",200,12) }
, { 3 , Belt(3,"ADT",400,20) }
};
Also you might be interested to have a look at the Prototype Design Pattern. That's an alternative technique you can use, and gives you better flexibility.
If you're only going to have a fixed set of values to deal with, I'd suggest making static const instances in Belt. This has the advantage of avoiding any lookup overhead, and dealing with invalid input (e.g., somebody passes INT_MAX to your constructor). For example:
class Belt {
private:
int _id;
std::string _name;
int _perimeter;
int _nOfPoints;
Belt(int id, name, perimeter, nOfPoints)
: _id{id}, _name{std::move(name)}
, _perimeter{perimeter}, _nOfPoints{nOfPoints} { }
public:
static const Belt neo(1, "NEO", 100, 10);
static const Belt ped(2, "PED", 200, 12);
// ...
};
A user can create a local Belt by copying one of the existing objects, and still perform any local manipulations that they need.
int main() {
auto myBelt = Belt::neo;
myBelt.some_member_function();
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have a vector that stores objects of class IdKaart.
std::vector<IdCard *> IdCard_vect;
Below the class definition:
#ifndef IDCARD_H
#define IDCARD_H
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class Lock;
class IdCard {
public:
IdCard(string, string, string);
string userId();
void giveAccess(Lock*);
void removeAccess(Lock*);
bool hasAccess(Lock*);
private:
string id;
vector<Lock*> access;
string name, adress;
};
#endif // IDCARD_H
I need to be able to find an object in above vector by comparing a string with "id". Considering this id is private, member function "userId()" is used to return this string.
When above object is found, I need to be able to call the giveAccess(Lock *) function.
You can use std::find_if:
std::string idToFind = …;
auto it = std::find_if(IdCard_vect.begin(), IdCard_vect.end(),
[&](IdCard* card) { return card->userId() == idToFind; });
if (it != IdCard_vect.end()) {
// card was found, can be accessed with `*it`.
}
or a good old for-if:
IdCard* result = nullptr;
for (IdCard* card : IdCard_vect)
if (card->userId() == idToFind)
result = card;
If you can't/don't want to use lambdas, you can create a custom predicate functor:
struct pointerIdCompare : public std::unary_function<IdCard*, bool>
{
pointerIdCompare(const std::string &id) : _id(id) {}
bool operator() (const IdCard* idCard)
{ return idCard->userId() == _id; }
std::string _id;
};
And then use it in find_if to get an iterator:
std::vector<IdCard*>::const_iterator cIt = std::find_if(IdCard_vect.begin(), IdCard_vect.end(), pointerIdCompare("some-id"));
You then use this iterator to call giveAccess:
if ( cIt != IdCard_vect.end() )
{
(*cIt)->giveAccess(...);
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm writing a cheat for an offline game, and have a class called Player which is responsible for getting and setting values in another process. However, my design for this class is very poor because the use of the class Player looks very messy and ugly, very difficult to read, and maintain
// declare variables here to read
if (Player.getthis() && Player.getthat() && Player.getthat() ... and so on)
//do stuff
class Player {
...
public:
...
// either of these calls can fail, so I return TRUE on success and FALSE on failure
BOOL GetHealth(float& health);
BOOL SetHealth(float& health);
...
};
So my question is, what is a better way of doing this?
Also: I don't necessarily need to read every single value of Player in memory, only a few at a time. That is why I don't have a single method such as BOOL UpdatePlayer() which will read everything and update the player
Here is how I would do it:
class Player {
public:
class AccessException : public std::exception {
friend class Player;
public:
virtual const char *what() const noexcept {
return "Error getting property with key " + key;
}
private:
AccessException(const std::string &key)
: key(key)
{}
std::string key;
};
float GetHealth() {
if (is_error) {
throw AccessException("health");
}
return health;
}
float GetPosX() {
if (is_error) {
throw AccessException("posX");
}
return posX;
}
};
void do_stuff() {
try {
float health = player.GetHealth();
float posX = player.GetPosX();
// Use health and posX...
} catch (const AccessException &ex) {
std::cerr << ex.what() << std::endl;
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
As a practice program after learning C++, I am developing a text-based game. I am using object-oriented programming style for handling the worlds/their objects. Here's the necessary information about their definitions:
class Object
{
private:
unsigned int id;
public:
unsigned int getID() const { return id; }
};
class TakeableObject: public Object
{
...
};
class EdibleObject: public TakeableObject
{
private:
float healthEffect;
float staminaEffect;
public:
float getHealthEffect() const { return healthEffect; }
float getStaminaEffect() const { return staminaEffect; }
};
class Player
{
private:
float health;
float stamina;
TakeableObject inventory[256];
public:
eat(const EdibleObject* o)
{
health += o->getHealthEffect();
stamina += o->getStaminaEffect();
}
eat(int id)
{
if (inventory[id] == NULL)
throw "No item with that ID!";
eat((EdibleObject) inventory[id]);
inventory[id] = NULL;
}
};
So my question is - in Player::eat(int), is there a way I can make sure the Object at Player::inventory[id] is an EdibleObject (perhaps through exception handling?)
User dynamic cast to check the object type at runtime.
Or you can use a virtual function with default definition in parent and can update it as per your requirement in derived classes.
Instead of eat((EdibleObject) inventory[id]); use the following
EdibleObject *temp = dynamic_cast<EdibleObject *>( &inventory[id] );
if(temp) { eat(*temp); }
else { /* Handling */ }
Your code suffers Object splicing, make sure to get rid of that first.