Where to place in game object definitions? - c++

This may sound like a stupid question, but I'm not sure how else to do this.
In my c++ ASCII-based roguelike, I will have lots and lots of Objects. Each allocated, in-game, object will have some properties in common. (Name, Size, ObjectID, Appearance, Etc.) Normally, I would use static variables for this, but that would require creating a new class and initializer for each and every Object. Instead, I've decided have each allocated object contain a pointer to a given ObjectDef, which I can then use to get around this. I will create a new class for a given type of object, when the object has new functionality that needs to be implemented.
That said, where do I define all of these object definitions? I'd like to have them in arrays, but I know global variables are bad, bad, bad.
Some general tips would be great. Thanks.
class WorldObjectDef //WHAT WE HAVE A LIST OF
{
protected:
std::string m_name;
float m_size;
int m_type;
int m_id;
AsciiNode m_node;
public:
WorldObjectDef(std::string, float, int, int, const AsciiNode &);
int getId() const;
std::string getName() const;
float getSize() const;
AsciiNode getNode() const;
};
class WorldObject //WHAT'S ALLOCATED IN A LEVEL
{
WorldObjectDef * m_def;
public:
WorldObject(const WorldObjectDef &);
int getId() const;
std::string getName() const;
float getSize() const;
AsciiNode getNode() const;
};
Something I've been wondering: Is there anything wrong with html-like code tags? God it's annoying to space indent every line.

I often create List<> that holds all the active objects ( ie. objects that are ingame and in use), that can be used to manipulate all the data in one loop.
That list could be defined anywhere, where its visibility is high enought. If it needs to be global, then so be it. Better to get the code working, than think if its running at max fps.
Dont use globals and gotos are the first warnings i remember to read about. Im not saying you should ignore those warnings, but to understand why its not good practice to use em in large scale.
Globals are bad, becouse they stay live until program exist, or manually disposed. If you have main loop, witch i think you have, you should define those variables in it.

I really think there's a problem here.
You don't necessarily need a new class definition for each object type in your game world (Chair, Table, Pencil); but you should have a class definition for each category of object based on the type of behavior that object can have.
For example, a Cat versus a Chair. A cat can probably move around under it's own power, make noises, etc. A chair on the other hand might be moved by a player, sat in, or even turned into firewood or whatever.
So, you'd have a top level class definition for WorldObject of which you would derive an Animal class and maybe an InanimateClass. The Animal class might have a type enumeration for Dog, Cat or Zebra. While the InanimateClass might be further subdivided depending on actions that characters may take with them.
All of these objects would be stored in a List and you could test the object types to determine what operations you can take on them.
This way you can keep the attributes of the objects with the object instances themselves and save yourself a LOT of work.

Related

How to "deep freeze" object like in JavaScript?

As we know, in JavaScript, we can freeze an object in runtime such that it will be immutable, furthermore, we can recursively freeze its mutable members such that it can no longer be modified from now on. Is it possible to achieve similar thing in C++?
I am aware of that this will inevitably cause an overhead and I am OK with it. My biggest problem is my class will have public members, and it looks like there is no way to stop a non-const reference owner from changing a public member directly.
EDIT: I am going to describe the design problem I am facing and suggest some solution.
We want to parse a musical sheet (in MusicXML form) into our internal hierarchical data structure, after this, our business logic will use the data structures and retrieve needed info from it. Our internal data structure needn't and shouldn't be modified after the parsing procedure. Because parsing procedure is pretty complex, we cannot make everything const and we have to modify the object after creation, so the "freezing" idea is natural here to prevent unintended modification to our DS.
Some ideas I have:
Spam getters and setters in my classes, and add a freezed flag for every class. (Most straightforward, but not tidy.)
Use some accessor helper classes to achieve this read only limitation.
It is too complex, and it is not worthwhile to freeze the objects.
The solution is to use const.
Say you have a class MusicalSheet. You can define getters and setters for whatever data you want. Make the setters const so you can't call them on a const object or reference.
class MusicalSheet
{
public:
void setNote(size_t position, Note note);
const Note& getNote(size_t position) const;
private:
// Data members
};
Then you have your parsing logic and business logic, and main to tie them together:
void parseMusic(MusicalSheet &sheet, Input &input);
void businessLogic(const MusicalSheet &sheet);
int main()
{
MusicalSheet sheet;
Input input(...);
parseMusic(sheet, input);
businessLogic(sheet);
}
Your parsing function has a non const reference to the object, so it can call setNote to fill in the data. The business logic can only access getNote as it's marked const. And getNote returns a const reference, so the inner object is also not modifiable by the business logic.
The example MusicalSheet class is obviously over simplified, and can in fact be replaced with just a std::vector<Note>, using operator[] to get and set the individual notes (along with many other functions). Like MusicalSheet, with a const vector you can only access the inner objects, not modify them.
Read the documentation on the const type qualifier and const-qualified member functions
One caveat with const is pointers. Making an int* const will give you a int* const, which is a constant pointer to a non-constant int. This is also true for smart pointers.
To get around it you can do something like this:
class DataHolder
{
public:
std::unique_ptr<Data>& getData() { return _data; }
const Data* getData() const { return _data.get(); }
private:
std::unique_ptr<Data> _data;
};
Now with a DataHolder you can reassign the pointer (e.g. dataHolder.getData() = std::make_unique<Data>(...);), but with a const DataHolder all you can do is access a const Data*.

Correct OOP-design, if I want to call non-const function of const reference?

I guess I still have to learn a lot about not only C++, but object oriented programming itself. In a recent C++-project, I came across one question quite frecuently: If I have a situation where I want to pass a const reference to some object, how can I use non-const functions of that object?
Let me give an example: Say I have a class with some data and a function with a small calculation with that data, for instance
class Person
{
private:
float weight;
float height;
float age;
...
public:
float bodyMassIndex();
};
Now I have another class with different expertise, e.g.
class GymInstructor
{
private:
float knowledge;
int age;
...
public:
int recommendDumbbellWeight(const Person &person);
};
Now say the function GymInstructor::recommendDumbbellWeight wants to use the function Person::bodyMassIndex() in its calculation.
Here is the list of things I should avoid or cannot do:
Making a local copy of the Person inside recommendDumbbellWeight (so avoid something like GymInstructor::recommendDumbbellWeight(Person person)) because I do not need to and it slows down my program
Giving a pointer to recommendDumbbellWeight by something like GymInstructor::recommendDumbbellWeight(Person *pPerson), because I just nead read-only access and should therefore avoid any errors by giving write-access to recommendDumbbellWeight
Make Person::bodyMassIndex a const function, because it depends on the state of the object, here e.g. weight and height.
Moving the function bodyMassIndex() to some other class, because it uses the data of the Person, so there is no real reason why another object should perform that calculation. If so, I would have to pass all the data to that other class.
Say, GymInstructor::recommendDumbbellWeight needs a lot more results of small calculations like Person::bodyMassIndex(), then I also should avoid just passing the result of the calculation with something like GymInstructor::recommendDumbbellWeight(float bodyMassIndex, float experience, float fitness, ... because it blows up my parameter list which looks ugly and produces unnecessary code.
So what is actually left? I would love to call Person::bodyMassIndex() in GymInstructor::recommendDumbbellWeight(const Person &person), but I can't, because person is a const reference.
I assume that either I am too stupid to see the very obvious solution or there is something fundamentally wrong in my design. How would I solve my problem?
Declaring a method const is somewhat like making a promise that it won't try to modify the object. It will not deny you access to the object state and you still will be perfectly able to call it for non-const objects.
So yes, the solution is float bodyMassIndex() const;
Declare method as const since it's a getter anyways
float bodyMassIndex() const;
The requirement that Person::bodyMassIndex() should not be const is unreasonable and quite ridiculous.
The only argument that Person::bodyMassIndex() should not be const is that it actually changes the state of the Person object. It doesn't.
So having Person::bodyMassIndex() non-const in the first place is a bug. A mistake in the class design.

Usage of const data member in C++

Well, I know the functionality of const data member in a C++ class.
What I want to know is, the purpose of introducing a const data member in a class. Why someone will use that while writing a real software? What are the real-life usage of const data members?
Please give me a few real life examples with reasons.
EDIT :
I am not asking about static const data member.
I am asking for some real life use cases where each object will be having a different const value for same data.
You'd use a const data member for the same reason that you'd use any const object: for a value that may be arbitrarily initialised but then never changed.
A good rule of thumb is to denote something as const "by default", so you can picture plenty of reasons to use it in a class.
class User
{
User(const std::string& name)
: name(name)
{}
private:
/**
* User's name is an invariant for the lifetime of this object.
*/
const std::string name;
};
Can you leave out the const here? Yeah, sure. But then you may accidentally change name when you didn't mean to. The entire purpose of const is to protect against such accidents.
However, sadly, your class will not be assignable!
There are several cases. The most obvious one is a static const data member. These are used as scoped constants:
class Something {
static const int SOME_CONSTANT = 17;
};
Note that under C++11 and onward, constexpr usually makes more sense in those cases.
This defines a constant that is typed and scoped to the class' implementation. I suspect this was not what you were asking, however.
The more interesting use case is for values that are different between instances of the class, but constant across the class' lifetime.
For example, suppose you have a RAID implementation, where a configuration sets the stripe width. You do not know the stripe width at compile time, so the above construct will not help you. You do want the width to remain constant throughout the class' lifetime however (maybe your code doesn't know how to handle stripe width changes).
In those cases, marking the value const, and setting it in the constructor, can give you compile time guarantee that no one is changing this value.
You use it exactly the same as you would use a globally declared const, only you want it to only apply to the class you have defined it in. For example
class Character
{
public:
Character()
:
mCurrentHealth{TOTAL_HEALTH},
mCurrentMana{TOTAL_MANA}
{
}
// Define lose/gain health/mana functions
// for mCurrentHealth and mCurrentMana
private:
int mCurrentHealth;
int mCurrentMana;
// Constants
const int TOTAL_HEALTH = 100;
const int TOTAL_MANA = 50;
};
There are many other examples, but the main point is that we don't want TOTAL_HEALTH and TOTAL_MANA defined outside the class, because they won't be relevant.

Downside to using pointers to allow classes to act as a data templates for creating instances of another class

I have been stumbling over this issue for a while now where I end up wanting to separate the data from the class I want to make and turn it into a pointer in the class.
Say for example I wanted to create an Item Class for an RPG game I keep trying to go:
class ItemTemplate
{
public:
enum TYPE { //Item types here. };
//ctor's and methods here.
private:
std::string m_name;
int m_buyprice;
int m_sellprice;
TYPE m_type;
int m_maxUses;
}
Basically the ItemTemplate is used to define any data that is constant for all instances of any Item object of that type like so:
const ItemTemplate cPotionTemplate( "Potion" , HEALING , 300 , 50 , 3 );
says all potions are called "Potion", are of the HEALING item types, cost 300G and sell for 50g and have 3 uses to start. None of that data is ever going to change. It would probably be more accurate for it to be HealingItemTemplate and to also say how much it recovers but that's getting off the point.
After that I want to create another class
class Item
{
public:
//ctors and methods here.
private:
ItemTemplate* m_Data;
int m_usesLeft;
}
Basically this just accesses the data in the ItemTemplate and tracks the number of uses the item still has.
What I am trying for is to cut down on the number of variables existing in memory when the program is running.
I know I could bundle all of this data into a single class but that would mean that every item would store a copy of data that doesn't or shouldn't change.
Taking sizeof(int) to be 4, sizeof(type) to be 4, sizeof(string) to be 4 and sizeof( a pointer ) to be 4.
The way I keep trying to implement it uses 8 bytes for each instance of an item but doing the bundled way would use 24 + ( m_name.capacity() or m_name.size() * sizeof(char) ) I know the latter doesn't accurately account for reserved space, but I'm not sure of the former.
Regardless, bundling all the data together in one class would use a minimum of 3x the number of bytes separating the data does. What I am struggling to understand is the downside of such an approach. My current thoughts are that it would be an increase in function calls and copies of data being made. I'm thinking that making the Item class a friend of the ItemTemplate class would be able to eliminate what I would consider a large portion of that increase in calls, those to the accessors.
Basically I'm just really struggling to fully understand the downside of the trade-off I keep wanting to make.
So what are the possible drawbacks to using such an implementation?
What methods exist to help determine when such an implementation is still worth using? If it matters for this I am using Code::Blocks 13.12 IDE but am woefully un-knowledgeable when it comes to using debuggers.
Is there another way to achieve this behavior that I'm missing?
I had considered templates but that seemed too rigid in terms of storing them as each derivation of the ItemTemplate class would create a new type Item<Derived Class> and no Item<type> would be able to be stored together unless they were from the same derivation. Which could work for some systems but isn't the desired implementation as it would make adding new Itemtypes much more of a chore.
An interface class in C++ would solve your concerns regarding the templates:
class ItemInterface
{
public:
enum TYPE { potion, scroll };
//ctor's and methods here.
public:
virtual std::string getName();
virtual int get_buyprice();
virtual int get_sellprice();
virtual TYPE get_type();
virtual int get_maxUses();
};
template<ItemInterface::TYPE T>
class item : ItemInterface {
private:
//Note, not all static members need to be constant
static const std::string m_name;
static const int m_buyprice;
static const int m_sellprice;
static const TYPE m_type;
static const int m_maxUses;
int m_usesLeft;
public:
item();
/*your getters implementation here*/
std::string getName(){return m_name;}
//etc...
};
//Your specialisations here.
//This looks ugly because it's private and const.
//Public static initialization would look better.
template<> const std::string item<ItemInterface::potion>::m_name = "potion";
//...
template<> const std::string item<ItemInterface::scroll>::m_name = "scroll";
You have identified two designs from the design patterns book.
Prototype pattern
Flyweight pattern
Prototype pattern
wikipedia prototype pattern
This assumes the construction of things can be achieved by defining available attributes and constructing a prototype. It simplifies the amount of subclassing needed, as the difference is only the parameters to the object.
Flyweight pattern
wikipedia : flyweight pattern
This pattern identifies that the state of many instanced objects may be split between "all these are the same" and these are the movable/usable attributes.
You are right to identify that these patterns have both advantages, and disadvantages, but whether they are appropriate, is based on your usage, not easy for people outside of your project to answer.

Trying to assign a new derived object to a base class pointer but it seems to act like nothing happened

Thanks in advance for the replies.
store() is a function of Backpack class which is holding an array of pointers (Item * items). The arguments sent to store() are correct (tested by printing them out with cout). displayInventory() still prints the previous Item object's members at the end of the function.
void store(string & name, float weight, int power, int slot)
{
items[slot] = new Weapon(name, weight, power); // Weapon is a derived class of Item
this->displayInventory();
}
Thanks.
EDIT: Researching vectors now.
First, here are a couple of things which might ease your life (and the life of those who will read your code). It would simplify your code. Hence it will make easier to understand and debug:
Use relevant names for your variables.
Example:
void store(string & name, float weight, int power, int slot)
{
items[slot] = new Weapon(name, weight, power);
numItems+=1;
this->getInventory();
}
Use relevant / consistent names for your methods.
Here, it's hard to understand what is the purpose of getInventory() because it starts with get, yet its return type isvoid. (Maybe you meant buildInventory()?)
You don't need to redefine in your derive class, what is already in the base class.
In particular you don't need to redefine name, weight and power (and their getters) in Weapon, since it's already defined in Item
If you don't define any constructor in a class, the compiler will provide a default one without arguments.
It means you can remove the line Container(){;}
Don't reinvent the wheel. You'd better use a std::vector rather than trying to handling yourself pointers and arrays.
I'm pretty sure this last advice can by itself fix your issue. In particular, if you use a vector<Item>, you won't need to manipulate pointers yourself anymore. It means no more new and no more delete.