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();
}
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 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 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 5 years ago.
Improve this question
Given a header file that has different functions (function1 and function2): what is the best practice of sharing the same default arguments?
class MyClass {
public:
virtual ... function1(..., int param1 = 48, int param2 = getStuff(99)) = 0;
virtual ... function2(..., int param1 = 48, int param2 = getStuff(99)) = 0;
}
Using something like
#define PARAM1 = 48
#define PARAM2 = getStuff(99)
seems rather inconvenient. I am fairly new to C++ so I don't know whats the best practice in this case. Should I instead create some private constant inside of MyClass?
You may do:
class MyClass {
public:
void function1(int param1 = default_param1, int param2 = default_param2());
void function2(int param1 = default_param1, int param2 = default_param2());
private:
static const int default_param1 = 48;
static int default_param2() { return getStuff(99); } // assuming it might change
};
I see your functions are virtual - be aware that the default parameters are not inherited!
int getStuff(int n)
{
return n;
}
class MyClass
{
public:
static constexpr int DefaultParam1 = 48;
static constexpr int DefaultParam2 = 99;
virtual ~MyClass() = default;
virtual void function1(int param1 = DefaultParam1, int param2 = DefaultParam2) = 0;
inline void function2()
{
function1(getStuff(DefaultParam1), getStuff(DefaultParam2));
}
inline void function2(int param1)
{
function1(param1, getStuff(DefaultParam2));
}
virtual void function2(int param1, int param2) = 0;
};
Have a look at function2 in my example, it is overloaded with inline functions. Advantage:
class MC : public MyClass
{
public:
virtual void function1(int param1, int param2)
{
}
using MyClass::function2;
virtual void function2(int param1, int param2)
{
}
};
int main()
{
MC mc;
((MyClass&)mc).function1();
mc.function2();
return 0;
}
function1 requires a cast to be used with default parameters (without repeating them in the inheriting class), function2 does not (unfortunately, you need the using clause to make the overloads visible in the inheriting class, though).
Side note: I'm not telling the first approach is wrong or bad, I'm just showing an alternative...
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.
We have a legacy C++ DB application, which I'll just oversimplify here: Over a dozen very wide DB tables represent partly similar kinds of data, so there is some overlap in the columns. The schema changes only slightly every few months, but the interface to it is dynamic, where table_name.column_name is looked up and represented by an ID. When we deal with the data in memory, it is all in a list, with each field having its ID associated.
This works well, but addressing data is messy. We have a lookup function for IDs based on a string (get_ID( type_A1, "title" )), and where we have code dealing with a specific type, colleagues tend to write the IDs literally. I would want to generate symbolic names corresponding to the string, so that much of this can be looked up at compile time. My naive idea went like:
struct ANY {
virtual const int
title, aaa, bbb, ccc, ddd; // ...
}
struct A1 : ANY {
const int
title=17, aaa=29, bbb=5, ddd=27;
}
struct B1 : ANY {
const int
title=71, aaa=92, ccc=45;
}
And usage would be either direct A1::bbb or B1::aaa where we know which type we are dealing with or:
const ANY& any = determine_type();
int title_id = any.title;
Alas C++ allows none of this, only methods can be virtual. :-( One solution might be wrapping them in methods:
struct ANY {
virtual int get_title() const = 0;
virtual int get_aaa() const = 0;
}
struct B1 : ANY {
const int
title=71, aaa=92, ccc=45;
int get_title() const { return title; };
int get_aaa() const { return aaa; };
}
For thousands of consts this approach feels so wrong! Another solution might be doing the dynamic part via an indirect name and lookup function:
enum names { title_name, aaa_name, bbb_name, ccc_name };
struct ANY {
virtual int get( names ) const = 0;
}
struct B1 : ANY {
const int
title=71, aaa=92, ccc=45;
static const int[] my_consts = { title, aaa, -1, ccc }; // pseudo code
int get( names n ) const { return my_consts[n]; };
}
This means having all identifiers in two variants – ugly! Does anybody have a clean, intuitive and space efficient solution?
An enum might be the better idea.
enum fields { title, aaa, bbb, ccc };
struct ANY {
virtual int get(field f);
};
struct A1 : public ANY {
virtual int get(field f) {
switch (f) {
case title : return 71;
//
}
}
};