I'm working on an application which among other things downloads items that belong to a certain category form a server. I want to make the downloader look like this:
class Downloader
{
Downloader(const ItemCategoryBase &category);
...
}
Each class derived from ItemCategoryBase will provide it's category ID trough a virtual function (in fact that's the only thing each derived class will do).
The issue I'm having is that I have a total of 120 item categories and writing a derived class for each one is going to be painful.
I've considered using a primitive to hold the ID but, I do not wish to implement range checking and throw exceptions in case the ID is out of range mainly because category IDs aren't all part of the same interval.
What I'm looking for is an efficient way of writing code that would fit the scheme above.
Any help is highly appreciated.
If you really have determined that this is the right way to do things, then I would suggest writing a code generator to handle it for you: create a CSV document containing all the Category ID's, and write an app that inserts each ID into template header/source files, and saves it out.. (For instance, put "$CATEGORY_ID" in wherever the Category ID goes in the files, and then just do a replace on "$CATEGORY_ID" with each ID in turn.)
However, I'm not sure I understand your statement: "I've considered using a primitive to hold the ID but, I do not wish to implement range checking and throw exceptions in case the ID is out of range mainly because category IDs aren't all part of the same interval." I can't imagine a case in which you wouldn't have to handle the complexity somewhere in your application anyway, and the range checking wouldn't be hard: just put all the valid Category IDs into a list structure of whatever your ID type is, and a simple index lookup call can answer whether the ID is part of that list.
If I have misunderstood you, what exactly is it about your setup that makes dealing with 120 ItemCategoryBase derived classes simpler than one ItemCategoryBase base class validated against a list of the IDs? You say "mainly because category IDs aren't all part of the same interval," so perhaps the checking against a list would give you what you need there. Otherwise, can you explain a bit more about how it works? Although I realize there are always exceptions, 120 classes doing nothing other than providing different IDs really strikes me as something that's unlikely to be a solution that will serve you well in the long run.
Since you're using C++, why not use templates and specify a non-type template parameter containing the ID?
For example, supposing that the category is an integer:
template<int category_id>
class Downloader : public ItemCategoryBase
{
public:
virtual int get_id()
{
return category_id;
}
};
You might as well let the compiler do the work for you.
Related
I'm a beginner programmer (who has a bunch of design-related scripting experience for video games but very little programming experience - so just basic stuff like loops, flow control, etc. - although I do have a C++ fundamentals and C++ data structures and algorithm's course under my belt). I'm working on a text-adventure personal project (I actually already wrote it in Python ages ago before I learned how classes work - everything is a dictionary - so it's shameful). I'm "remaking" it in C++ with classes to get out of the rut of having only done homework assignments.
I've written my player and room classes (which were simple since I only need one class for each). I'm onto item classes (an item being anything in a room, such as a torch, a fire, a sign, a container, etc.). I'm unsure how to approach the item base class and derived classes. Here are the problems I'm having.
How do I tell whether an item is of a certain type in a non-shit way (there's a good chance I'm overthinking this)?
For example, I set up my print room info function so that in addition to whatever else it might do, it prints the name of every object in its inventory (i.e. inside of it) and I want it to print something special for a container object (the contents of its inventory for example).
The first part's easy because every item has a name since the name attribute is part of the base item class. The container has an inventory though, which is an attribute unique to the container subclass.
It's my understanding that it's bad form to execute conditional logic based on the object's class type (because one's classes should be polymorphic) and I'm assuming (perhaps incorrectly) that it'd be weird and wrong to put a getHasInventory accessor virtual function in the item base class (my assumption here is based on thinking it'd be crazy to put virtual functions for every derived class in the base class - I have about a dozen derived classes - a couple of which are derived classes of derived classes).
If that's all correct, what's an acceptable way to do this? One obvious thing is to add an itemType attribute to the base and then do conditional logic but this strikes me as wrong since it seems to just be a re-skinning of the checking class type solution. I'm unsure whether the above-mentioned assumptions are correct and what a good solution might be.
How should I structure my base class/classes and my derived classes?
I originally wrote them such that the item class was the base class and most other classes used single inheritance (except for a couple which had multi-level).
This seemed to present some awkwardness and repeating myself though. For example, I want a sign and a letter. A sign is a Readable Item > Untakeable Item > Item. A letter is a Readable Item > Takeable Item > Item. Because they all use single inheritance I need two different Readable Items, one that's takeable and one that's not (I know I could just make takeable and untakeable into attributes of the base in this instance and I did but this works as an example because I still have similar issues with other classes).
That seems icky to me so I took another stab at it and implemented them all using multiple inheritance & virtual inheritance. In my case that seems more flexible because I can compose classes of multiple classes and create a kind of component system for my classes.
Is one of these ways better than the other? Is there some third way that's better?
One possible way to solve your problem is polymorphism. By using polymorphism you can (for example) have a single describe function which when invoked leads the item to describe itself to the player. You can do the same for use, and other common verbs.
Another way is to implement a more advanced input parser, which can recognize objects and pass on the verbs to some (polymorphic) function of the items for themselves to handle. For example each item could have a function returning a list of available verbs, together with a function returning a list of "names" for the items:
struct item
{
// Return a list of verbs this item reacts to
virtual std::vector<std::string> get_verbs() = 0;
// Return a list of name aliases for this item
virtual std::vector<std::string> get_names() = 0;
// Describe this items to the player
virtual void describe(player*) = 0;
// Perform a specific verb, input is the full input line
virtual void perform_verb(std::string verb, std::string input) = 0;
};
class base_torch : public item
{
public:
std::vector<std::string> get_verbs() override
{
return { "light", "extinguish" };
}
// Return true if the torch is lit, false otherwise
bool is_lit();
void perform_verb(std::string verb, std::string) override
{
if (verb == "light")
{
// TODO: Make the torch "lit"
}
else
{
// TODO: Make the torch "extinguished"
}
}
};
class long_brown_torch : public base_torch
{
std::vector<std::string> get_names() override
{
return { "long brown torch", "long torch", "brown torch", "torch" };
}
void describe(player* p) override
{
p->write("This is a long brown torch.");
if (is_lit())
p->write("The torch is burning.");
}
};
Then if the player input e.g. light brown torch the parser looks through all available items (the ones in the players inventory followed by the items in the room), get each items name-list (call the items get_names() function) and compare it to the brown torch. If a match is found the parser calls the items perform_verb function passing the appropriate arguments (item->perform_verb("light", "light brown torch")).
You can even modify the parser (and the items) to handle adjectives separately, or even articles like the, or save the last used item so it can be referenced by using it.
Constructing the different rooms and items is tedious but still trivial once a good design has been made (and you really should spend some time creating requirement, analysis of the requirements, and creating a design). The really hard part is writing a decent parser.
Note that this is only two possible ways to handle items and verbs in such a game. There are many other ways, to many to list them all.
You are asking some excellent questions reg. how to design, structure and implement the program, as well as how to model the problem domain.
OOP, 'methods' and approaches
The questions you ask indicate that you have learned about OOP (object-oriented programming). In a lot of introductory material on OOP, it is common to encourage modelling the problem domain directly through objects and subtyping and implementing functionality by adding methods to them. A classical example is modelling animals, with for instance an Animal type and two sub-types, Duck and Cat, and implementing functionality, for instance walk, quack and mew.
Modelling the problem domain directly with objects and subtyping can make sense, but it can also very much be overkill and bothersome compared to simply having a single or a few types with different fields describing what it is. In your case, I do believe a more complex modelling like you have with objects and subtypes or alternative approaches can make sense, since among other aspects you have functionality that varies depending on the type as well as somewhat complex data (like a container with an inventory). But it is something to keep in mind - there are different trade-offs, and sometimes, having a single type with multiple different fields for modelling the domain can make more sense overall.
Implementing the desired functionality through methods on a base class and subtypes likewise have different trade-offs, and it is not always a good approach for the given case. For one of your questions, you could do something like adding a print method or similar to the base type and each subtype, but this is not always that nice in practice (a simple example is that of a calculator application where simplifying the arithmetic expression the user enters (like (3*x)*4/2) might be bothersome to implement if one uses the approach of adding methods to the base class).
Alternative approach - Tagged unions/sum types
There is a very nice fundamental abstraction known as "tagged union" (it is also known by the names "disjoint union" and "sum type"). The main idea about the tagged union is that you have a union of several different sets of instances, where which set the given instance belongs to matters. They are a superset of the feature in C++ known as enum. Regrettably, C++ does not currently support tagged unions, though there are research into it (for instance https://www.stroustrup.com/OpenPatternMatching.pdf , though this may be somewhat beyond you if you are a beginner programmer). As far as I can see, this fits very well with the example you have given here. An example in Scala would be (many other languages support tagged unions as well, such as Rust, Kotlin, Typescript, the ML-languages, Haskell, etc.):
sealed trait Item {
val name: String
}
case class Book(val name: String) extends Item
case object Fire extends Item {
val name = "Fire"
}
case class Container(val name: String, val inventory: List[Item]) extends Item
This describes your different kinds of items very well as far as I can see. Do note that Scala is a bit special in this regard, since it implements tagged unions through subtyping.
If you then wanted to implement some print functionality, you could then use "pattern matching" to match which item you have and do functionality specific to that item. In languages that support pattern matching, this is convenient and non-fragile, since the pattern matching checks that you have covered each possible case (similar to switch in C++ over enums checking that you have covered each possible case). For instance in Scala:
def getDescription(item: Item): String = {
item match {
case Book(_) | Fire => item.name
case Container(name, inventory) =>
name + " contains: (" +
inventory
.map(getDescription(_))
.mkString(", ") +
")"
}
}
val description = getDescription(
Container("Bag", List(Book("On Spelunking"), Fire))
)
println(description)
You can copy-paste the two snippets in here and try to run them: https://scalafiddle.io/ .
This kind of modelling works very well with what one might call "data types", where you have no or very little functionality in the classes themselves, and where the fields inside the classes basically are part of their interface ("interface" in the sense that you would like to change the implementations that uses the types if you ever add to, remove or change the fields of the types).
Conversely, I find a more conventional subtyping modelling and approach more convenient when the implementation inside of a class is not part of its interface, for instance if I have a base type that describes a collision system interface, and each of its subtypes have different performance characteristics, handy for different situations. Hiding and protecting the implementation since it is not part of the interface makes a lot of sense and fits very well with what one might call "mini-modules".
In C++ (and C), sometimes people do use tagged unions despite the lack of language support, in various ways. One way that I have seen being used in C is to make a C union (though do be careful reg. aspects such as memory and semantics) where an enum tag was used to differentiate between the different cases. This is error-prone, since you might easily end up accessing a field in one enum case that is not valid for that enum case.
You could also model your command input as a tagged union. That said, parsing can be somewhat challenging, and parsing libraries may be a bit involved if you are a beginner programmer; keeping the parsing somewhat simple might be a good idea.
Side-notes
C++ is a special languages - I do not quite like it for cases where I do not care much about resource usage or runtime performance and the like for multiple different reasons, since it can be annoying and not that flexible to develop in. And it can be challenging to develop in, because you must always take great care to avoid undefined behaviour. That said, if resource usage or runtime performance do matter, C++ can, depending on case, be a very good option. There are also a number of very useful and important insights in the C++ language and its community, such as RAII, ownership and lifetimes. My recommendation is that learning C++ is a good idea, but that you should also learn other languages, maybe for instance a statically-typed functional programming language. FP (functional programming) and languages supporting FP, has a number of advantages and drawbacks, but some of their advantages are very, very nice, especially reg. immutability as well as side-effects.
Of these languages, Rust may be the closest to C++ in certain regards, though I don't have experience with Rust and cannot therefore vouch for either the language or its community.
As a side-note, you may be interested in this Wikipedia-page: https://en.wikipedia.org/wiki/Expression_problem .
I am trying to design a class that would wrap shader parameter in such way that it would enable the user to easily set and get its value without a need to write a tonne of validation code outside of this class implementation.
The problem is that obviously the shader parameter values can be of different types, and whether I use templates or method overloading it results in a lot of messy code that if one was to use this class it would probably not be a very pleasant experience.
Is there some clever design pattern that once implemented would render the usage of said class to be more straightforward? I wouldn't mind if the mechanism was more complex as long as its implementation is not exposed to the user of this class.
Also just to be more clear, this shader parameter class is somewhat abstract in that its purpose is only to store the parameter for easier editing and handling across my code base. It does not interact or have any knowledge about the actual shader.
Edit 1:
Here's how I attempted to solve the issue before with templates and why I failed:
My template values were derived from a non template base class that I used to store them in a STL containers, but I have run into issues when retrieving the values and being unable to up cast them back into their template values, another issue was the amount of code needed to set and get the values when using this class implementation
Edit 2:
The ideal usage would be :
ShaderParameter* param = ShaderParameterCollection.GetParameter("color_param");
ShaderParameterCollection->GetParameter("property_name")->Set(vec3());
ShaderParameterCollection->GetParameter("property_name")->Get(&out);
ShaderParameterCollection->AddParameter("property_name", FLOAT_VEC3, vec3());
ShaderParamterCollection is just a storage class that internally uses STL container, does mapping and validation, I already have that one sorted.
What about a templated value class ? It's not a particular design pattern but could suit your needs pretty well by encapsulating :
1) your private shader data of different types and their public accessors
2) the validation code to be executed when the data are changing (coded in setters for example)
I would start by replacing the string property names that you currently have with typed keys, for example:
ShaderParameterKey<color> color_key("color_param");
ShaderParameterKey<vec3> property_key("property_name");
Then your collection methods could take a ShaderParameterKey<T> as input and return a ShaderParameter<T>. Your usage would look like:
ShaderParameter<color>* param = ShaderParameterCollection.GetParameter(color_key);
ShaderParameterCollection->GetParameter(property_key)->Set(vec3());
ShaderParameterCollection->GetParameter(property_key)->Get(&out);
ShaderParameterCollection->AddParameter(property_key, vec3());
You no longer need to pass the type (FLOAT_VEC3) to AddParameter because that is encoded in the key.
I'm not sure what issues you ran into in your previous attempt with the template base class but this solution calls for something similar.
My goal here is to create a unique ID (starting a 0) for each child of a specific class. I'm not sure if it is possible in the way i want, but i figured i'd ask here as a last resort.
Some context:
I'm creating my own 2D game engine and i want it to have an ECS as it's back bone (Before anyone says anything, i'm doing this as a learning experience, i know i could just use an already existing game engine). My idea is that each class that implements the 'EntityComponent' class should have a unique ID applied to it. This needs to be per child, not per object. I want to use this ID as the index for an array to find the component of an entity. The actual ID that each Component gets is unimportant and each component does not need to be assigned the ID every run time.
My hope is there is some way to create something similar to a static variable per class (That implements the Entity Component class). It needs to be quick to get this value so doing an unordered_map lookup is slower than i would like. One thing i do not want to do is setting the ID for every component myself. This could cause problems once many components are made and could cause problems if i forget to set it or set two components to the same ID.
One idea i had was to make a variable in EntityComponent called ID (And a getter to get it). When the entity is constructed it looks up an unordered map (which was made at run time, assigning an ID to each class) for what ID it should have. The price of looking up once at construction is fine. The only problem i see with this is there is a lot of redundant data (Though overall it seems it would account to a pretty small amount). With this, every single transform component would have to store that it its ID is x. This means potentially thousands upon thousands of transform components are storing this ID value, when only 1 really needs to.
Basically i am after an extremely quick way to find an ID for a class TYPE. This can be through a lookup, but it needs to be a quick lookup. I would like something faster than unordered_map if possible. If this can be done through compile time tricks (Maybe enums?) or maybe even templates i would love to hear your ideas. I know premature optimisation is the bad, but being able to get a component fast is a pretty big thing.
What i'm asking might very well be impossible. Just thought i'd ask here to make sure first. I should also note i'm trying to avoid implementation of this in the children classes. I'd like to not have to set up the same code for each child class to create an id.
Thank you.
In order to get something corresponding to the actual type of an object, it either needs to be in the object itself or accessed via a virtual function. Otherwise the type will be determined by the type of the variable it is associated with.
A common option when speed and size are both important is to have an integer identifier associated with each type (when the full type list is known at compile time) and use that integer value in a specific way when you want to do something based on the type.
The integer mechanism usually uses an enum for generating the corresponding value for each type and has that field in every object.
The virtual method variety, I've used boost::uuid and a static data member in each class and a virtual method get'er for it.
Declare a virtual function newId() in EntityComponent.
Implement this function to get and increment a static variable in each class, which children you want to have a unique Id.
Assign Id in the constructor:
mId = newId();
don't know this if this is what you meant and i know this is an old post however this is how im currently dealing with a similar issue, maybe it will help someone else.
(Im also doing this as a learning experience for uni :) )
in the controlling class or its own utility class:
enum class EntityType{ TYPE_ONE = 0, TYPE_TWO =1};
in class header:
#include "EntityType.h"
class Whatever{
public:
inline void getType(){return _type;}
OR
inline void getType(){return EntityType::TYPE_ONE;}
private:
EntityType _type = EntityType::TYPE_ONE;
};
Hope this is helpful to anyone :)
I want to have specific methods with a specific pattern recognized at compile time and registered along with a specified id trough mixins in a parent class.
ex.:
take a method 'X' from a class with a predetermined id:5, what I want is that, in a mixin in a parent class, method X will be registered as a delegate with its id to be called later on by its id.
What would be the best way to specify the Id considering I want the id to be of type int and only the specified methods to be registered?
should I (if it is even possible) do it with a custom annotation pretty much like the #property but with an argument, like:
#autoregister(id)
void method(...)
if it is possible to do it this way, an example or a link to the documentation on how to do it would be nice since I didn't find it in the documentation.
if it is not possible I'll use the function's signature as a string instead but I really want to do it with a numeric identifier instead of a possibly quite long string as much as possible.
Making custom annotations is not possible at the moment (but it will be in the future).
However, you can make your own method-naming convention that will allow you to do something similar to what you have described. I do not have time to think deeply how to accomplish this, but I would start with having a method like:
public void id30_doSomething(/* params */) {
// body
}
alias id30_doSomething doSomething;
// finally, lets do something with all these methods
// and generate mixin...
After this you could probably list all methods and find if their names match id([0-9]*)_.*, if so, then you generate mixin to register them in the parent...
I have a class, let's say Person, which is managed by another class/module, let's say PersonPool.
I have another module in my application, let's say module M, that wants to associate information with a person, in the most efficient way. I considered the following alternatives:
Add a data member to Person, which is accessed by the other part of the application. Advantage is that it is probably the fastest way. Disadvantage is that this is quite invasive. Person doesn't need to know anything about this extra data, and if I want to shield this data member from other modules, I need to make it private and make module M a friend, which I don't like.
Add a 'generic' property bag to Person, in which other modules can add additional properties. Advantage is that it's not invasive (besides having the property bag), and it's easy to add 'properties' by other modules as well. Disadvantage is that it is much slower than simply getting the value directly from Person.
Use a map/hashmap in module M, which maps the Person (pointer, id) to the value we want to store. This looks like the best solution in terms of separation of data, but again is much slower.
Give each person a unique number and make sure that no two persons ever get the same number during history (I don't even want to have these persons reuse a number, because then data of an old person may be mixed up with the data of a new person). Then the external module can simply use a vector to map the person's unique number to the specific data. Advantage is that we don't invade the Person class with data it doesn't need to know of (except his unique nubmer), and that we have a quick way of getting the data specifically for module M from the vector. Disadvantage is that the vector may become really big if lots of persons are deleted and created (because we don't want to reuse the unique number).
In the last alternative, the problem could be solved by using a sparse vector, but I don't know if there are very efficient implementations of a sparse vector (faster than a map/hashmap).
Are there other ways of getting this done?
Or is there an efficient sparse vector that might solve the memory problem of the last alternative?
I would time the solution with map/hashmap and go with it if it performs good enough. Otherwise you have no choice but add those properties to the class as this is the most efficient way.
Alternatively, you can create a subclass of Person, basically forward all the interface methods to the original class but add all the properties you want and just change original Person to your own modified one during some of the calls to M.
This way module M will see the subclass and all the properties it needs but all other modules would think of it as just an instance of Person class and will not be able to see your custom properties.
The first and third are reasonably common techniques. The second is how dynamic programming languages such as Python and Javascript implement member data for objects, so do not dismiss it out of hand as impossibly slow. The fourth is in the same ballpark as how relational databases work. It is possible, but difficult, to make relational databases run the like the clappers.
In short, you've described 4 widely used techniques. The only way to rule any of them out is with details specific to your problem (required performance, number of Persons, number of properties, number of modules in your code that will want to do this, etc), and corresponding measurements.
Another possibility is for module M to define a class which inherits from Person, and adds extra data members. The principle here is that M's idea of a person differs from Person's idea of a person, so describe M's idea as a class. Of course this only works if all other modules operating on the same Person objects are doing so via polymorphism, and furthermore if M can be made responsible for creating the objects (perhaps via dependency injection of a factory). That's quite a big "if". An even bigger one, if nothing other than M needs to do anything life-cycle-ish with the objects, then you may be able to use composition or private inheritance in preference to public inheritance. But none of it is any use if module N is going to create a collection of Persons, and then module M wants to attach extra data to them.