Lets say we have some association, modeled as a class, which has several bank accounts on which it accepts donations. The public can donate to each of these, or get a list of all bank accounts from the charity, pick one, and then donate directly to some specified account.
Of course, the association will only return a const& to its bank accounts so that the public cannot arbitrarily change (or even replace) them. But it would still be nice that - after getting the const& to the accounts and then picking one (by index), a user will be directly able to donate to the account - i.e using a member method of the account, and not having to go back to the association itself, remember the number of account, etc.
I came up with the following solution, which seems to work:
namespace detail {
class VirtualAssociation {
public:
virtual void donate(size_t account_number, int amount) = 0;
};
}
class DonationsAccount {
public:
DonationsAccount(detail::VirtualAssociation* association, size_t account_number) :
_association(association), _account_number(account_number), _money(0) {}
/*! put some money on this account. Of course not const */
void put(int amount) {_money += amount;}
/*! Donate some money. Will be const, but actually does the same as the put() method*/
void donate(int amount) const {_association->donate(_account_number, amount); }
/*! Get balance of this account */
int balance() const {return _money; }
private:
detail::VirtualAssociation* _association;
size_t _account_number;
int _money;
};
class Association : public detail::VirtualAssociation {
public:
Association() : _accounts() {_accounts.emplace_back(this, 0); }
/*! Donate some money on a certain account of this association */
void donate(size_t account_number, int amount) override {_accounts[account_number].put(amount); }
/*! Get the list of accounts of this association */
const std::vector<DonationsAccount>& accounts() const {return _accounts; }
private:
std::vector<DonationsAccount> _accounts;
};
int main() {
Association association;
association.donate(0,10);
// association.accounts()[0].put(); //illegal, because put is a non-const method
association.accounts()[0].donate(5);
std::cout << "Balance on account 0: " << association.accounts()[0].balance() << std::endl;
return 0;
}
gcc compiles this with no warnings, and i also get the correct print output of 15. But of course this feels like an ugly workaround, so my questions are
Does the above yield undefined behaviour? At least we (indirectly) change the object state of an association when calling a const-classified method.
In case this is undefined behaviour: will this be defined again if I declare the _money attribute of the DonationsAccount to be mutable? Could you expand on what mutable exactly does and why it helps (if it does)?
Is there a better way to achieve the above behaviour?
For further clarification, some remarks:
I am not actually dealing with accounts etc, this is just a made up example that semantically (more or less) fits. So this is not about security etc, but const-correctness of my program
To be more concrete, the Association in above example corresponds to some graph managing (and owning) nodes and edges. Nodes and edges don't exist outside of a graph, since this would be semantically meaningless. I want to grant users access to the nodes of this graph (stored in a vector), but of course not allow the user to just swap out this vector etc, so I return a const reference. It would however still make sense that the user can call stuff like "add an edge" on certain nodes, since I can control these semantically correct operations on nodes and ensure things like range-checking etc, which is handled by the graph itself.
So essentially, I would like to return a reference that is not const (since we want to allow for adding edges etc), but has a state that forbids stuff like assignment / deletion / moving the object away, but allows certain methods like "add an edge", "remove node" (this will have side effects on the graph that have to be controlled, thus this is different from just deleting the node)
Related
I'm trying to declare a vector containing user objects in the header file, but I'm unsure of how to use the setter and getter functions to push values objects back to the vector or call them again.
class userbase
{
public:
userbase();
virtual ~userbase();
//FUNCTION DECLARATIONS
void record_User(user);
void setUserVector(vector<user> const &newUser) {
//userbase_V = newUser;
userbase_V.push_back(newUser);
}
vector<user> const &getUservector() const {
return userbase_V;
}
protected:
private:
vector <user> userbase_V;
};
Getters/setters are quite often misunderstood. The aim of using such functions is encapsulation which means restricting access to your data or exposing certain functions.
The reason why we don't make private members public in the first place is because there are some operations that we don't want users of our class to perform.
Consider the following class:
class userbase
{
public:
vector<user> users;
};
Let's say the goal of the userbase class is to manage a loyal, unwavering list of followers of an application. And since users is a public member, we can do whatever we want with it:
class company
{
public:
void massacre()
{
m_userbase.users.clear(); // Aaaaahhh!!!
}
private:
userbase m_userbase;
};
What? Where did all our loyal, unwavering followers go? We can't just remove our users!
The company class has access to all of std::vector's functionality on m_userbase.users. But really, from userbase's point of view, we don't want the outside to access particular functions (in this case, clear() or erase()). We want to restrict what operations can be performed (modifiers) and what attributes can retrieved (accessors). That is, we want to encapsulate the users vector.
Making userbase a private member is the first step:
class userbase
{
private:
vector<user> users;
};
Now let's add some naive "encapsulation" to see if it solves our problem. (This is where a lot of misunderstanding stems from.)
Here's our new class:
class userbase
{
public:
void setUsers(vector<user> const& newUsers) {
users = newUsers;
}
vector<user> const& getUsers() const {
return users;
}
private:
vector<user> users;
}
Can the company still clear the users vector directly? Yes.
class company
{
public:
void massacre()
{
auto users = m_userbase.getUsers();
users.clear();
m_userbase.setUsers(users); // Aaaaahhh!!!
// or simply create a new vector with no data
m_userbase.setUsers(std::vector<user>{}); // Aaaaahhh!!!
}
private:
userbase m_userbase;
};
So simply providing getters/setters doesn't solve the issue.
The common approach is to instead approach it the other way around. Instead of asking "What don't I want the outside to do?", ask "What do I want to allow the outside to do?". This way, you can figure what sort of functionality to expose. This is part of designing a good API.
Maybe our API wants to be able to: add a user, get a user's name, and count the number of users. Then we would design a class like this:
class userbase
{
public:
/// modifiers:
// Add a user to the userbase.
void addUser(User const& user);
/// accessors:
// Returns the user's name given its index.
string getUserName(size_t index) const;
// Returns the number of users belonging to this userbase.
size_t numberOfUsers() const;
private:
vector<user> m_users;
};
The takeaway is: it's up to you to decide what "the outside" can or can't do with its members. You'll need to spend more time thinking and less time writing code, but this is normal.
Further reading:
Why use getter and setters? (A good read even though it's tagged with Java.)
I have a situation where class A, B, and C, all are derived from X to make a composite pattern.
Now A, B, and C are very similar but they do have different internal attributes. My question is how do I access their attributes and modify them once they are added to composite without typecasting it?
In my real example, the part-whole relationship perfectly makes sense and all elements support the main operation which is why I need it. That said individual classes in the composite does have different attributes and requires special operations.
Is there a way to decouple these special properties and functions related to them away from composite class but attach to them?
To put things in perspective, let's say we have composite merchandise (base class of composite) which has a price. Now a store is a merchandise, in it, a department is a merchandise, in which an actual item say a potis merchandise, it can have a pot-set with combination pots which is also merchandise and so on.
class Merchandise
{
public:
virtual void add(Merchandise* item) = 0;
virtual Merchandise* getMerchandise() = 0;
virtual void show() = 0;
// assume we have the following key operations here but I am not implementing them to keep this eitemample short
//virtual setPrice(float price) = 0;
//virtual float getPrice() = 0;
};
class Store : public Merchandise
{
vector< Merchandise*> deparments;
std::string storeName = "";
public:
Store(std::string store_name) : storeName(store_name) {}
virtual void add(Merchandise* item)
{
deparments.push_back(item);
}
virtual Merchandise* getMerchandise()
{
if (deparments.size() > 0)
return deparments[0];
return 0;
}
virtual void show()
{
cout << "I am Store " << storeName << " and have following " << deparments.size() << " departments" << endl;
for (unsigned int i = 0; i < deparments.size(); i++)
{
deparments[i]->show();
}
}
};
class Department : public Merchandise
{
std::string depName;
vector<Merchandise*> items;
public:
Department(std::string dep_name) : depName(dep_name) {}
virtual void add(Merchandise* item)
{
items.push_back(item);
}
virtual Merchandise* getMerchandise()
{
if (items.size() > 0)
return items[0];
return 0;
}
virtual void show()
{
cout << "I am department " << depName << " and have following " << items.size() << " items" << endl;
for (unsigned int i = 0; i < items.size(); i++)
{
items[i]->show();
}
}
};
class Shirt : public Merchandise
{
std::string shirtName;
public:
Shirt(std::string shirt_name) : shirtName(shirt_name) {}
virtual void add(Merchandise* item) {}
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am shirt " << shirtName << endl;
};
};
class Pot : public Merchandise
{
std::string potName;
public:
Pot(std::string pot_name) : potName(pot_name) {}
virtual void add(Merchandise* item) { }
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am pot " << potName << endl;
};
int num = 0;
};
class CookSet : public Merchandise
{
std::string cooksetName;
vector<Merchandise*> pots;
public:
CookSet(std::string cookset_name) : cooksetName(cookset_name) {}
vector<Merchandise*> listOfPots;
virtual void add(Merchandise* item) { pots.push_back(item); }
virtual Merchandise* getMerchandise() { return 0; }
virtual void show()
{
cout << "I am cookset " << cooksetName << " and have following " << pots.size() << " items" << endl;
for (unsigned int i = 0; i < pots.size(); i++)
{
pots[i]->show();
}
};
int num = 0;
};
int main()
{
// create a store
Store * store = new Store( "BigMart");
// create home department and its items
Department * mens = new Department( "Mens");
mens->add(new Shirt("Columbia") );
mens->add(new Shirt("Wrangler") );
// likewise a new composite can be dress class which is made of a shirt and pants.
Department * kitchen = new Department("Kitchen");
// create kitchen department and its items
kitchen->add(new Pot("Avalon"));
CookSet * cookset = new CookSet("Faberware");
cookset->add(new Pot("Small Pot"));
cookset->add(new Pot("Big pot"));
kitchen->add(cookset);
store->add( mens );
store->add(kitchen);
store->show();
// so far so good but the real fun begins after this.
// Firt question is, how do we even access the deep down composite objects in the tree?
// this wil not really make sense!
Merchandise* item = store->getMerchandise()->getMerchandise();
// Which leads me to want to add specific method to CStore object like the following to retrieve each department
// but then does this break composite pattern? If not, how can I accomodate these methods only to CStore class?
//store->getMensDept();
//store->getsKitchenDept();
// Likewise a shirt class will store different attributes of a shirt like collar size, arm length etc, color.
// how to retrieve that?
// Other operations is, say if item is cookset, set it on 20% sale.
// Another if its a shirt and color is orange, set it on 25% sale (a shirt has a color property but pot doesn't).
// how to even dispaly particular attributes of that item in a structure?
// item->getAttributes();
return 0;
}
The problem is with this line once I have filled up the composite.
Merchandise* item = store->getMerchandise()->getMerchandise();
First, from my code structure, I know this should be a certain type but as a best practice, we are not supposed to typecast this!? But I do want to change its properties which are unique to it so how do I achieve that?
Assume this store sells shirts as well and I want to change its properties (or even just to display them!), it is very different from a pot.
What would be the best approach here? I think if we can somehow decouple the unique properties of each composite into different classes, this way composite will stay leaner too but not sure how to achieve that.
I assume, in real life, there is no perfect composite and the constituent classes will have some differences. How do we handle that?
Update
Please note I have used the merchandise example to explain the problem. In my real example, A, B, C are all derived from X. A contains multiple B which contains multiple C items. When an operation is performed on A, it needs to be performed on its constituents and that's why I am using composite. But then, each composite does have different attributes. Is composite not a good fit for this?
I think you are looking for the visitor design pattern, it keeps clean interfaces and makes code much more flexible.
class Shirt;
class Pot;
class visitor{
public:
//To do for each component types:
virtual void visit(Shirt&) =0;
virtual void visit(Pot&) =0;
};
class Merchandise
{
public:
//...
//Provides a default implementation for the acceptor that
//that do nothing.
virtual void accept(visitor& x){}
// assume we have the following key operations here but I am not implementing them to keep this eitemample short
//virtual setPrice(float price) = 0;
//virtual float getPrice() = 0;
// => implementable with a visitor
};
class Store : public Merchandise
{
//...
void accept(visitor& v) override
{
for (unsigned int i = 0; i < deparments.size(); i++)
{
//forward the visitor to each component of the store.
//do the same for departments
deparments[i]->accept(v);
}
}
};
class Shirt : public Merchandise
{
//...
void accept(visitor& v) override{
//now *this as the type Shirt&, pass this to the visitor.
v.visit(*this);
}
};
class Pot : public Merchandise
{
//...
void accept(visitor& v) override{
v.visit(*this);
}
};
class SpecialPromotion
:public visitor{
public:
void visit(Shirt& s) override {
//25% discount on orange shirts, 15% otherwise;
if (s.color="orange")
s.price*=0.75;
else
s.price*=0.85
}
void visit(Pot& p) override{
//one pot offered for each pot pack
++p.num;
}
};
//example of usage:
void apply_special_promotion(Store& s){
SpecialPromotion x;
s.accept(x);
}
class EstimateStockMass
:public visitor{
public:
double mass=0;
void visit(Shirt& s) override {
if (s.size="XL") mass+=0.5;
else mass+=0.1;
}
void visit(Pot& p) override{
mass += p.num * 1.2;
}
};
//example of usage:
double get_stock_mass(Store& s){
EstimateStockMass x;
s.accept(x);
return x.mass;
}
It seems like what you want to do is gathering RTTI (Run-time type information), so dynamic_cast is the solution. Also, if you are using C++17, I will recommend you use std::variant (or boost::variant if you are using lower version of C++ but are using boost.) If you do not want to use them, then maybe you can make your add a template function and returns a reference to the underlying type.
By the way
in your main there are a bunch of dynamic allocations that never get deallocated. Use smart pointers if you have C++ with version at least C++11.
your base classes do not have virtual destructors, this will cause huge problems when destroying your store
Don't use using namespace std
If you have C++11, use override keyword when you want to override a virtual function
You should mark show() const.
Merchandise: a commodity offered for sale
Now a store is a merchandise,
This is true only if you are selling the store. Otherwise it is better described as a container of merchandise, not a composite.
Even if you are in the business of selling stores, it might (depending on the context of the program) be prudent to treat it as a different kind of merchandise (different base class) since the selling environment is rather different.
in it, a department is a merchandise,
Departments within a store are rarely sold to other stores, so I highly doubt this claim. Again, you have something that contains merchandise, not something composed of merchandise.
in which an actual item say a pot is merchandise, it can have a pot-set with combination pots which is also merchandise and so on.
Yes, this much is good. Pots are offered for sale. A pot-set combination sounds like a good example of composite merchandise, as the set is offered for sale, and its components might be packaged and offered for sale separately, perhaps even on the same shelf.
Speaking of the shelf, that would be another example of a container of merchandise.
It looks like you might be after containers rather than composites. A store could have a vector of departments (or perhaps a set if you want to find them by name). The department in turn could have a container of merchandise within that department. Or perhaps the department would contain aisles, which then contain shelves, which then contain merchandise.
If you need the inventory of the entire store, there are a few options. One would be to have the store iterate over its departments, which then iterate over their inventories. Ideally, you would implement this within the store class so that code outside the class does not need to know about this structure. Another option would be for the store to maintain its own container of merchandise. This would mean that a single item of merchandise would logically be in multiple containers (e.g. a store's and a department's). This suggests using containers of shared_ptr, so that each item of merchandise is still represented by a single data object.
Regardless of the implementation chosen, the relationship between "store" and "merchandise" is better described as "has" rather than "is".
Concerning Your Design Choices
Let's compare the GoF book description of the intent of the Composite pattern with your requirements:
Compose objects into tree structures that represent whole-part hierarchies.
In your example a shirt is not part of a shop, and a shop is not really an item of merchandise.
You say this does make sense in your actual code, but I can only comment on the code you actually showed.
Composite lets clients treat individual objects and compositions of objects uniformly.
In your comment you say you don't really want to treat each type of object uniformly.
So, it's at least not obvious that Composite is a good fit, because the description doesn't match your use case (at best, it half-fits your described use case but not your sample code).
For comparison, the motivating example from that book is a drawing app, where treating the main canvas as a Drawable object containing other Drawable sub-objects (of different types like lines, polygons and text) is useful for rendering. In that case each object is a drawable part of the drawable whole, and it focuses on the case when you do want to treat them uniformly (ie, issuing a single draw call to the top-level canvas).
A match has an innings (has score/result), both side which are playing has their inning (has scores), then each player who is playing has his innings (score with more details). When match progresses, an event is added to the match which than is added to current innings and than current player innings. So I build up score this way but at the end I want to display it and each innings type is rather different and setting up current state requires different operations.
OK, an innings is part of a match, but do you have any more levels? Does an innings consist of balls or other events, or is it just ... an innings number, a player and a score?
If you can easily model a game as a list of innings, and link each innings to a player for per-player reports, that seems a lot simpler.
Even if you have another level, if you only want to deal with objects heterogeneously (according to their different types, instead of homogeneously as if they're all the same), you can just write that structure explicitly.
Concerning Your Composite Implementation
The getMerchandise interface is poor. Why does it return only the first of potentially many objects? Why do you need to get them anyway?
You mention two use cases:
changing an object's properties
Presumably you know which object you want to alter, right? Say you want to change the price of the object loosely identified as Mens>Shirts>Wrangler. Either
ask the store to forward a Visitor to that object by name (so the store finds the department called "Mens" and asks that to forward the Visitor to a child matching Shirts>Wrangler).
just find the Shirt("Wrangler") object directly in some other index (eg. by stock number) and deal with it directly. You don't have to do everything via the Composite pattern even if you do use it.
displaying an object
But the whole point of the Composite pattern is that every object should implement a virtual display (or whatever) method. You use this when you want to let every type know how to display itself.
In many places you can read that dynamic_cast means "bad design". But I cannot find any article with appropriate usage (showing good design, not just "how to use").
I'm writing a board game with a board and many different types of cards described with many attributes (some cards can be put on the board). So I decided to break it down to the following classes/interfaces:
class Card {};
class BoardCard : public Card {};
class ActionCard : public Card {};
// Other types of cards - but two are enough
class Deck {
Card* draw_card();
};
class Player {
void add_card(Card* card);
Card const* get_card();
};
class Board {
void put_card(BoardCard const*);
};
Some guys suggested that I should use only one class describing a card. But I would mean many mutually excluding attributes. And in the case of the Board class' put_card(BoardCard const&) - it is a part of the interface that I cannot put any card on the board. If I had only one type of card I would have to check it inside the method.
I see the flow like the following:
a generic card is in the deck (it's not important what its type is)
a generic card is drawn from the deck and given to a player (the same as above)
if a player chosen a BoardCard then it can be put on the board
So I use dynamic_cast before putting a card on the board. I think that using some virtual method is out of the question in this case (additionally I wouldn't make any sense to add some action about board to every card).
So my question is: What have I designed badly? How could I avoid dynamic_cast? Using some type attribute and ifs would be a better solution...?
P.S.
Any source treating about dynamic_cast usage in the context of design is more than appreciated.
Yes, dynamic_cast is a code smell, but so is adding functions that try to make it look like you have a good polymorphic interface but are actually equal to a dynamic_cast i.e. stuff like can_put_on_board. I'd go as far as to say that can_put_on_board is worse - you're duplicating code otherwise implemented by dynamic_cast and cluttering the interface.
As with all code smells, they should make you wary and they don't necessarily mean that your code is bad. This all depends on what you're trying to achieve.
If you're implementing a board game that will have 5k lines of code, two categories of cards, then anything that works is fine. If you're designing something larger, extensible and possibly allowing for cards being created by non-programmers (whether it's an actual need or you're doing it for research) then this probably won't do.
Assuming the latter, let's look at some alternatives.
You could put the onus of applying the card properly to the card, instead of some external code. E.g. add a play(Context& c) function to the card (the Context being a means to access the board and whatever may be necessary). A board card would know that it may only be applied to a board and a cast would not be necessary.
I would entirely give up using inheritance however. One of its many issues is how it introduces a categorisation of all cards. Let me give you an example:
you introduce BoardCard and ActionCard putting all cards in these two buckets;
you then decide that you want to have a card that can be used in two ways, either as an Action or a Board card;
let's say you solved the issue (through multiple-inheritance, a BoardActionCard type, or any different way);
you then decide you want to have card colours (as in MtG) - how do you do this? Do you create RedBoardCard, BlueBoardCard, RedActionCard etc?
Other examples of why inheritance should be avoided and how to achieve runtime polymorphism otherwise you may want to watch Sean Parent's excellent "Inheritance is the Base Class of Evil" talk. A promising looking library that implements this sort of polymorphism is dyno, I have not tried it out yet though.
A possible solution might be:
class Card final {
public:
template <class T>
Card(T model) :
model_(std::make_shared<Model<T>>(std::move(model)))
{}
void play(Context& c) const {
model_->play(c);
}
// ... any other functions that can be performed on a card
private:
class Context {
public:
virtual ~Context() = default;
virtual void play(Context& c) const = 0;
};
template <class T>
class Model : public Context {
public:
void play(Context& c) const override {
play(model_, c);
// or
model_.play(c);
// depending on what contract you want to have with implementers
}
private:
T model_;
};
std::shared_ptr<const Context> model_;
};
Then you can either create classes per card type:
class Goblin final {
void play(Context& c) const {
// apply effects of card, e.g. take c.board() and put the card there
}
};
Or implement behaviours for different categories, e.g. have a
template <class T>
void play(const T& card, Context& c);
template and then use enable_if to handle it for different categories:
template <class T, class = std::enable_if<IsBoardCard_v<T>>
void play(const T& card, Context& c) {
c.board().add(Card(card));
}
where:
template <class T>
struct IsBoardCard {
static constexpr auto value = T::IS_BOARD_CARD;
};
template <class T>
using IsBoardCard_v = IsBoardCard<T>::value;
then defining your Goblin as:
class Goblin final {
public:
static constexpr auto IS_BOARD_CARD = true;
static constexpr auto COLOR = Color::RED;
static constexpr auto SUPERMAGIC = true;
};
which would allow you to categorise your cards in many dimensions also leaving the possibility to entirely specialise the behaviour by implementing a different play function.
The example code uses std::shared_ptr to store the model, but you can definitely do something smarter here. I like to use a static-sized storage and only allow Ts of a certain maximum size and alignment to be used. Alternatively you could use a std::unique_ptr (which would disable copying though) or a variant leveraging small-size optimisation.
Why not use dynamic_cast
dynamic_cast is generally disliked because it can be easily abused to completely break the abstractions used. And it is not wise to depend on specific implementations. Of course it may needed, but really rarely, so nearly everyone takes a rule of thumb - probably you should not use it. It's a code smell that may imply that you should rethink Your abstractions because they may be not the ones needed in Your domain. Maybe in Your game the Board should not have put_card method - maybe instead card should have method play(const PlaySpace *) where Board implements PlaySpace or something like that. Even CppCoreGuidelines discourage using dynamic_cast in most cases.
When use
Generally few people ever have problems like this but I came across it multiple times already. The problem is called Double (or Multiple) Dispatch. Here is pretty old, but quite relevant article about double dispatch (mind the prehistoric auto_ptr):
http://www.drdobbs.com/double-dispatch-revisited/184405527
Also Scott Meyers in one of his books wrote something about building double dispatch matrix with dynamic_cast. But, all in all, these dynamic_casts are 'hidden` inside this matrix - users don't know what kind of magic happens inside.
Noteworthy - multiple dispatch is also considered code smell :-).
Reasonable alternative
Check out the visitor pattern. It can be used as replace for dynamic_cast but it is also some kind of code smell.
I generally recommend using dynamic_cast and visitor as a last resort tools for design problems as they break abstraction which increases complexity.
You could apply the principles behind Microsoft's COM and provide a series of interfaces, with each interface describing a set of related behaviors. In COM you determine if a specific interface is available by calling QueryInterface, but in modern C++ dynamic_cast works similarly and is more efficient.
class Card {
virtual void ~Card() {} // must have at least one virtual method for dynamic_cast
};
struct IBoardCard {
virtual void put_card(Board* board);
};
class BoardCard : public Card, public IBoardCard {};
class ActionCard : public Card {};
// Other types of cards - but two are enough
class Deck {
Card* draw_card();
};
class Player {
void add_card(Card* card);
Card const* get_card();
};
class Board {
void put_card(Card const* card) {
const IBoardCard *p = dynamic_cast<const IBoardCard*>(card);
if (p != null) p->put_card(this);
};
That may be a bad example, but I hope you get the idea.
It seems to me that the two types of cards are quite different. The things a board card and an action card can do are mutually exclusive, and the common thing is just that they can be drawn from the deck. Moreover, that's not a thing a card does, it's a player / deck action.
If this is true, a question one should ask is whether they should really descend from a common type, Card. An alternative design would be that of a tagged union: let Card instead be a std::variant<BoardCard, ActionCard...>, and contain an instance of the appropriate type. When deciding what to do with the card, you use a switch on the index() and then std::get<> only the appropriate type. This way you don't need any *_cast operator, and get a complete freedom of what methods (neither of which would make sense for the other types) each type of card supports.
If it's only almost true but not for all types, you can variate slightly: only group together those types of cards that can sensibly be superclassed, and put the set of those common types into the variant.
I always found the usage of a cast a code smell, and in my experience, the 90% of the time the cast was due to bad design.
I saw usage of dynamic_cast in some time-critical application where it was providing more performance improvement than inherit from multiple interfaces or retrieving an enumeration of some kind from the object (like a type). So the code smelt, but the usage of the dynamic cast was worth it in that case.
That said, I will avoid dynamic cast in your case as well as multiple inheritances from different interfaces.
Before reaching my solution, your description sounds like there are a lot of details omitted about the behavior of the cards or the consequence they have on the board
and the game itself. I used that as a further constraint, trying to keep thing boxed and maintainable.
I would go for a composition instead of an inheritance. It will provide you evenly the chance of using the card as a 'factory':
it can spawn more game modifiers - something to be applied to the board, and one to a specific enemy
the card can be reused - the card could stays in the hands of the player and the effect on the game is detached from it (there is no 1-1 binding between cards and effects)
the card itself can sit back on the deck, while the effects of what it did are still alive on the board.
a card can have a representation (drawing methods) and react to the touch in a way, where instead the BoardElement can be evenly a 3d miniature with animation
See [https://en.wikipedia.org/wiki/Composition_over_inheritance for further details]. I'd like to quote:
Composition also provides a more stable business domain in the long term as it is less prone to the quirks of the family members.In other words, it is better to compose what an object can do (HAS - A) than extend what it is(IS - A).[1]
A BoardCard/Element can be something like this:
//the card placed on the board.
class BoardElement {
public:
BoardElement() {}
virtual ~BoardElement() {};
//up to you if you want to add a read() methods to read data from the card description (XML / JSON / binary data)
// but that should not be part of the interface. Talking about a potential "Wizard", it's probably more related to the WizardCard - WizardElement relation/implementation
//some helpful methods:
// to be called by the board when placed
virtual void OnBoard() {}
virtual void Frame(const float time) { /*do something time based*/ }
virtual void Draw() {}
// to be called by the board when removed
virtual void RemovedFromBoard() {}
};
the Card could represent something to be used in a deck or in the user's hands, I'll add an interface of that kind
class Card {
public:
Card() {}
virtual ~Card() {}
//that will be invoked by the user in order to provide something to the Board, or NULL if nothing should be added.
virtual std::shared_ptr<BoardElement*> getBoardElement() { return nullptr; }
virtual void Frame(const float time) { /*do something time based*/ }
virtual void Draw() {}
//usefull to handle resources or internal states
virtual void OnUserHands() {}
virtual void Dropped() {}
};
I'd like to add that this pattern allows many tricks inside the getBoardElement() method, from acting as a factory (so something should be spawned with its own lifetime),
returning an Card data member such as a std:shared_ptr<BoardElement> wizard3D; (as example), create a binding between the Card and the BoardElement as for:
class WizardBoardElement : public BoardElement {
public:
WizardBoardElement(const Card* owner);
// other members omitted ...
};
The binding can be useful in order to read some configuration data or whatever...
So inheritance from Card and from BoardElement will be used to implement the features exposed by the base classes and not for providing other methods that can be reached only through a dynamic_cast.
For completeness:
class Player {
void add(Card* card) {
//..
card->OnUserHands();
//..
}
void useCard(Card* card) {
//..
//someway he's got to retrieve the board...
getBoard()->add(card->getBoardElement());
//..
}
Card const* get_card();
};
class Board {
void add(BoardElement* el) {
//..
el->OnBoard();
//..
}
};
In that way, we have no dynamic_cast, Player and board do simple things without knowing about the inner details of the card they are handled, providing good separations between the different objects and increasing maintainability.
Talking about the ActionCard, and about "effects" that may be applied to other players or your avatar, we can think about having a method like:
enum EffectTarget {
MySelf, //a player on itself, an enemy on itself
MainPlayer,
Opponents,
StrongOpponents
//....
};
class Effect {
public:
//...
virtual void Do(Target* target) = 0;
//...
};
class Card {
public:
//...
struct Modifiers {
EffectTarget eTarget;
std::shared_ptr<Effect> effect;
};
virtual std::vector<Modifiers> getModifiers() { /*...*/ }
//...
};
class Player : public Target {
public:
void useCard(Card* card) {
//..
//someway he's got to retrieve the board...
getBoard()->add(card->getBoardElement());
auto modifiers = card->getModifiers();
for each (auto modifier in modifiers)
{
//this method is supposed to look at the board, at the player and retrieve the instance of the target
Target* target = getTarget(modifier.eTarget);
modifier.effect->Do(target);
}
//..
}
};
That's another example of the same pattern to apply the effects from the card, avoiding the cards to know details about the board and it's status, who is playing the card, and keep the code in Player pretty simple.
Hope this may help,
Have a nice day,
Stefano.
What have I designed badly?
The problem is that you always need to extend that code whenever a new type of Card is introduced.
How could I avoid dynamic_cast?
The usual way to avoid that is to use interfaces (i.e. pure abstract classes):
struct ICard {
virtual bool can_put_on_board() = 0;
virtual ~ICard() {}
};
class BoardCard : public ICard {
public:
bool can_put_on_board() { return true; };
};
class ActionCard : public ICard {
public:
bool can_put_on_board() { return false; };
};
This way you can simply use a reference or pointer to ICard and check, if the actual type it holds can be put on the Board.
But I cannot find any article with appropriate usage (showing good design, not just "how to use").
In general I'd say there aren't any good, real life use cases for dynamic cast.
Sometimes I have used it in debug code for CRTP realizations like
template<typename Derived>
class Base {
public:
void foo() {
#ifndef _DEBUG
static_cast<Derived&>(*this).doBar();
#else
// may throw in debug mode if something is wrong with Derived
// not properly implementing the CRTP
dynamic_cast<Derived&>(*this).doBar();
#endif
}
};
I think that I would end up with something like this (compiled with clang 5.0 with -std=c++17). I'm couroius about your comments. So whenever I want to handle different types of Cards I need to instantiate a dispatcher and supply methods with proper signatures.
#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <vector>
template <class T, class... Args>
struct any_abstract {
static bool constexpr value = std::is_abstract<T>::value || any_abstract<Args...>::value;
};
template <class T>
struct any_abstract<T> {
static bool constexpr value = std::is_abstract<T>::value;
};
template <class T, class... Args>
struct StaticDispatcherImpl {
template <class P, class U>
static void dispatch(P* ptr, U* object) {
if (typeid(*object) == typeid(T)) {
ptr->do_dispatch(*static_cast<T*>(object));
return;
}
if constexpr (sizeof...(Args)) {
StaticDispatcherImpl<Args...>::dispatch(ptr, object);
}
}
};
template <class Derived, class... Args>
struct StaticDispatcher {
static_assert(not any_abstract<Args...>::value);
template <class U>
void dispatch(U* object) {
if (object) {
StaticDispatcherImpl<Args...>::dispatch(static_cast<Derived *>(this), object);
}
}
};
struct Card {
virtual ~Card() {}
};
struct BoardCard : Card {};
struct ActionCard : Card {};
struct Board {
void put_card(BoardCard const& card, int const row, int const column) {
std::cout << "Putting card on " << row << " " << column << std::endl;
}
};
struct UI : StaticDispatcher<UI, BoardCard, ActionCard> {
void do_dispatch(BoardCard const& card) {
std::cout << "Get row to put: ";
int row;
std::cin >> row;
std::cout << "Get row to put:";
int column;
std::cin >> column;
board.put_card(card, row, column);
}
void do_dispatch(ActionCard& card) {
std::cout << "Handling action card" << std::endl;
}
private:
Board board;
};
struct Game {};
int main(int, char**) {
Card* card;
ActionCard ac;
BoardCard bc;
UI ui;
card = ∾
ui.dispatch(card);
card = &bc;
ui.dispatch(card);
return 0;
}
As I can't see why you wouldn't use virtual methods, I'm just gonna present, how I would do it. First I have the ICard interface for all cards. Then I would distinguish, between the card types (i.e. BoardCard and ActionCard and whatever cards you have). And All the cards inherit from either one of the card types.
class ICard {
virtual void put_card(Board* board) = 0;
virtual void accept(CardVisitor& visitor) = 0; // See later, visitor pattern
}
class ActionCard : public ICard {
void put_card(Board* board) final {
// std::cout << "You can't put Action Cards on the board << std::endl;
// Or just do nothing, if the decision of putting the card on the board
// is not up to the user
}
}
class BoardCard : public ICard {
void put_card(Board* board) final {
// Whatever implementation puts the card on the board, mb something like:
board->place_card_on_board(this);
}
}
class SomeBoardCard : public BoardCard {
void accept(CardVisitor& visitor) final { // visitor pattern
visitor.visit(this);
}
void print_information(); // see BaseCardVisitor in the next code section
}
class SomeActionCard : public ActionCard {
void accept(CardVisitor& visitor) final { // visitor pattern
visitor.visit(this);
}
void print_information(); // see BaseCardVisitor
}
class Board {
void put_card(ICard* const card) {
card->put_card(this);
}
void place_card_on_board(BoardCard* card) {
// place it on the board
}
}
I guess the user has to know somehow what card he has drawn, so for that I would implement the visitor pattern. You could also place the accept-method, which I placed in the most derived classes/cards, in the card types (BoardCard, ActionCard), depeneding on where you want to draw the line on what information shall be given to the user.
template <class T>
class BaseCardVisitor {
void visit(T* card) {
card->print_information();
}
}
class CardVisitor : public BaseCardVisitor<SomeBoardCard>,
public BaseCardVisitor<SomeActionCard> {
}
class Player {
void add_card(ICard* card);
ICard const* get_card();
void what_is_this_card(ICard* card) {
card->accept(visitor);
}
private:
CardVisitor visitor;
};
Hardly a complete answer but just wanted to pitch in with an answer similar to Mark Ransom's but just very generally speaking, I've found downcasting to be useful in cases where duck typing is really useful. There can be certain architectures where it is very useful to do things like this:
for each object in scene:
{
if object can fly:
make object fly
}
Or:
for each object in scene that can fly:
make object fly
COM allows this type of thing somewhat like so:
for each object in scene:
{
// Request to retrieve a flyable interface from
// the object.
IFlyable* flyable = object.query_interface<IFlyable>();
// If the object provides such an interface, make
// it fly.
if (flyable)
flyable->fly();
}
Or:
for each flyable in scene.query<IFlyable>:
flyable->fly();
This implies a cast of some form somewhere in the centralized code to query and obtain interfaces (ex: from IUnknown to IFlyable). In such cases, a dynamic cast checking run-time type information is the safest type of cast available. First there might be a general check to see if an object provides the interface that doesn't involve casting. If it doesn't, this query_interface function might return a null pointer or some type of null handle/reference. If it does, then using a dynamic_cast against RTTI is the safest thing to do to fetch the actual pointer to the generic interface (ex: IInterface*) and return IFlyable* to the client.
Another example is entity-component systems. In that case instead of querying abstract interfaces, we retrieve concrete components (data):
Flight System:
for each object in scene:
{
if object.has<Wings>():
make object fly using object.get<Wings>()
}
Or:
for each wings in scene.query<Wings>()
make wings fly
... something to this effect, and that also implies casting somewhere.
For my domain (VFX, which is somewhat similar to gaming in terms of application and scene state), I've found this type of ECS architecture to be the easiest to maintain. I can only speak from personal experience, but I've been around for a long time and have faced many different architectures. COM is now the most popular style of architecture in VFX and I used to work on a commercial VFX application used widely in films and games and archviz and so forth which used a COM architecture, but I've found ECS as popular in game engines even easier to maintain than COM for my particular case*.
One of the reasons I find ECS so much easier is because the bulk of the systems in this domain like PhysicsSystem, RenderingSystem, AnimationSystem, etc. boil down to just data transformers and the ECS model just fits beautifully for that purpose without abstractions getting in the way. With COM in this domain, the number of subtypes implementing an interface like a motion interface like IMotion might be in the hundreds (ex: a PointLight which implements IMotion along with 5 other interfaces), requiring hundreds of classes implementing different combinations of COM interfaces to maintain individually. With the ECS, it uses a composition model over inheritance, and reduces those hundreds of classes down to just a couple dozen simple component structs which can be combined in endless ways by the entities that compose them, and only a handful of systems have to provide behavior: everything else is just data which the systems loop through as input to then provide some output.
Between legacy codebases that used a bunch of global variables and brute force coding (ex: sprinkling conditionals all over the place instead of using polymorphism), deep inheritance hierarchies, COM, and ECS, in terms of maintainability for my particular domain, I'd say ECS > COM, while deep inheritance hierarchies and brute force coding with global variables all over the place were both incredibly hard to maintain (OOP using deep inheritance with protected data fields is almost as hard to reason about in terms of maintaining invariants as a boatload of global variables IMO, but further can invite the most nightmarish cascading changes spilling across entire hierarchies if designs need to change -- at least the brute force legacy codebase didn't have the cascading problem since it was barely reusing any code to begin with).
COM and ECS are somewhat similar except with COM, the dependencies flow towards central abstractions (COM interfaces provided by COM objects, like IFlyable). With an ECS, the dependencies flow towards central data (components provided by ECS entities, like Wings). At the heart of both is often the idea that we have a bunch of non-homogeneous objects (or "entities") of interest whose provided interfaces or components are not known in advance, since we're accessing them through a non-homogeneous collection (ex: a "Scene"). As a result we need to discover their capabilities at runtime when iterating through this non-homogeneous collection by either querying the collection or the objects individually to see what they provide.
Either way, both involve some type of centralized casting to retrieve either an interface or a component from an entity, and if we have to downcast, then a dynamic_cast is at least the safest way to do that which involves runtime type checking to make sure the cast is valid. And with both ECS and COM, you generally only need one line of code in the entire system which performs this cast.
That said, the runtime checking does have a small cost. Typically if dynamic_cast is used in COM and ECS architectures, it's done in a way so that a std::bad_cast should never be thrown and/or that dynamic_cast itself never returns nullptr (the dynamic_cast is just a sanity check to make sure there are no internal programmer errors, not as a way to determine if an object inherits a type). Another type of runtime check is made to avoid that (ex: just once for an entire query in an ECS when fetching all PosAndVelocity components to determine which component list to use which is actually homogeneous and only stores PosAndVelocity components). If that small runtime cost is non-negligible because you're looping over a boatload of components every frame and doing trivial work to each, then I found this snippet useful from Herb Sutter in C++ Coding Standards:
template<class To, class From> To checked_cast(From* from) {
assert( dynamic_cast<To>(from) == static_cast<To>(from) && "checked_cast failed" );
return static_cast<To>(from);
}
template<class To, class From> To checked_cast(From& from) {
assert( dynamic_cast<To>(from) == static_cast<To>(from) && "checked_cast failed" );
return static_cast<To>(from);
}
It basically uses dynamic_cast as a sanity check for debug builds with an assert, and static_cast for release builds.
I have this class:
class Phone {
private:
string producer, color;
int weight, dimension;
public:
Phone(string &producer, string &color, int &weight, int &dimension):
producer(producer), color(color), weight(weight), dimension(dimension) {};
Phone():
producer(""), color(""), weight(0), dimension(0) {};
virtual ~Phone() {};
string getProducer(void) const;
string getColor(void) const;
int getWeight(void) const;
int getDimension(void) const;
virtual void displayInfo(void) const;
};
The problem is here caused by the fact that I expose the internal implementation of the object via getters.
But how can I prevent this?
Because usually in my code, I need to know some private data from my object (for comparision is one example), and that's why I use getters.
So then I rewrite the class to something like this:
class Phone {
private:
string producer, color;
int weight, dimension;
public:
Phone(string &producer, string &color, int &weight, int &dimension):
producer(producer), color(color), weight(weight), dimension(dimension) {};
Phone():
producer(""), color(""), weight(0), dimension(0) {};
virtual ~Phone() {};
bool isTheProducer(string& producer) const { return this->producer == producer };
bool hasWeight(int& weight) const { return this->weight == weight };
bool hasDimension(int& dimension) const { return this->dimension == dimension };
virtual void displayInfo(void) const;
};
Is this a better design (by the fact that I don't get the actual private value)?
As you might have seen from the other answers and comments, the answer is: It depends.
In fact, it depends mainly on the usecases where your class is used. Let's stick first to the example given in the question, the comparison of objects. Since it is not clearly visible from the question if we want to compare two phone objects or just a specific data member I will discuss both situations here.
Comparing a data member to out-of-class data
Let's take this usecase where we search for all phones with a weight bigger than x(just pseudocode):
for (Phone& p in phoneList) {
if (p.getWeight() > x) {
cout << "Found";
}
}
Then the first class example is perfectly fine, since this is not an intrinsic feature of the phone, and thus the phone class is not responsible for handling it. In addition, the result does not expose more than absolutely required for the task.
Comparing two phone objects
In this case both code examples are equally good (or in this case equally bad). In both cases the user has to know a lot of details about how phones are represented to compare all necessary members. If in a later revision a new member is added to the class, every code segment that compares two phones has to be adapted. To overcome this, one can add a function to the class that does exactly the comparison.
class Phone {
private:
string producer, color;
int weight, dimension;
public:
bool IsEqualTo(const Phone& other)
{
return (producer == other.producer && color == other.color &&....);
}
Non comparitive usecase
But let's go to a more advanced example. Let's assume the following task: A user enters the pin to a phone and if it is the correct one, the phone should unlock. Let's assume a very naive approach:
class Phone
{
private:
int pin;
bool unlocked;
public:
int getPin() { return pin; }
void unlock() { unlocked = true; }
};
and the corresponding call
if (phone.getPin() == enteredPin)
phone.unlock();
In this case we have a totally different situation. Here we need to consider the "tell, don't ask" rule, which basically says that it is a bad design to query the state of an object first, make a decision and then tell the object what to do. Instead we should only tell the object what we want, and let it do the work for us. In this usecase this is obvious, since unlocking the phone only when the pin is correct is a responsibility of the phone, not of the user that uses the phone class. But in more complex scenarious many programmers will do exactly what I described here.
Back to the problem: A good solution here would be for example
class Phone
{
private:
int pin;
bool unlocked;
public:
void CheckPin(int enteredPin) {
if (pin == enteredPin)
unlocked = true;
}
};
with the code
phone.CheckPin(enteredPin);
Hope this helps, and thanks to #KonradRudolph for pointing to the "tell, don't ask rule". Feel free to help me to improve the answer per commenting on it :)
The first one, even with getter, is encapsulated. Consider the color() method, which returns a string. Even if you change the implementation of Phone such that you store the color as an enum rather than a string, your method can still return a string if you do some sort of conversion first. The important part is that you can change the implementation of color() and the underlying storage without users of the class needing to change.
Compare to a class that stores color as a publicly accessible string. If you later change the data member to an enum, you need to modify every location that uses the color. This is less of a property of encapsulation and more a property of separating interface from implementation.
Encapsulation allows controlling of attributes exclusively via methods within the class. Both examples are encapsulated.
Consider the following code:
class Rectangle
{
public:
// Constructors
Rectangle(){ init(0,0); }
Rectangle(int h, int w){ init(h,w); }
// Methods
void init(int h, int w)
{
_h = h;
_w = w;
}
// Getters / Setters
double get_h(void){ return _h; }
double get_w(void){ return _w; }
void set_h(double h){ _h = h; }
void set_w(double w){ _w = w; }
std::string get_name(void){ return _name; }
void set_name(std::string name){ _name = name; }
private:
// Private Members
int _h, _w;
std::string _name;
};
class House
{
public:
// <BEGIN PASSTHROUGHS>
std::string get_b_name(void){ return _base.get_name() };
std::string get_r_name(void){ return _roof.get_name() };
void set_b_name(std::string name){ _base.set_name(name); }
void set_r_name(std::string name){ _roof.set_name(name); }
// </END PASSTHROUGHS>
private:
// Private Members
Rectangle _base;
Triangle _roof;
};
This code works fine.
My question deals with the "passthrough" functions in the House class, enclosed by the PASSTHROUGHS tags. Is this the best way to do this? The arguments and return types will always match and there is no "intelligence" in these passthrough functions other than to make things cleaner and more straightforward.
My instinct would be something like one of the following:
get_b_name = _base.get_name;
// OR
std::string get_b_name(void) = _base.get_name;
... but neither seem to work unfortunately and it was only wishful thinking in the first place. If there are no easier options, telling me that is fine too. Thanks!
The problem, I think, is conceptual. Your design is quite un-object oriented in that the house does not represent an entity, but rather provides a bit of glue around the components. From that standpoint, it would make more sense to provide accessors to the elements, rather than pass-through functions:
class House {
Rectangle _base;
Triangle _roof;
public:
const Rectangle& base() const {
return _base;
}
const Triangle& roof() const {
return _roof;
}
};
I imagine that this is just a toy example, but the same reasoning applies: a class should represent an entity on which a set of operations are preformed, in some cases those operations might be implemented in terms of internal subobjects, but they are still operations on the type, and how they are gathered is an implementation detail.
Consider:
class House {
Thermostat t;
public:
int temperature() const {
return t.temperature();
}
};
From the user point of view the house has a temperature that can be read, and in this particular implementation, it is read from a thermostat that is a member. But that is an implementation detail. You might want to later install more thermostats in the house and substitute the single reading by an average of the readings, but that will not change the fact that the entity House (in this model) has a temperature.
That is, you should not be thinking in implementing pass-through functions, but rather on implementing features of the type. If the implementation happens to be a single forwarding to an internal method, that is fine.
But if the type contains internal members and it makes sense to access properties of the members, consider that it might be that you actual type should just provide access to its internal members. Consider that you want to move a piano inside the house, then you might just provide access to the door member and let the user check:
class House {
Door d;
public:
Door const & door() const {
return d;
}
};
bool can_enter_piano( House const & h, Piano const & p ) {
return h.door().width() > p.size();
}
There is no need to provide House::get_door_width(), and House::get_door_color() so that you can describe the entrance to a friend, and House::get_door_handle() so that they can know when they arrive...
That's possibly because your design is contradictory. Why on earth would you make a public member variable, then write a function that just forwards to one of that variable's functions? As a user of your class, I'd just call the function on the public variable myself. You're just confusing me by providing two ways to do the same thing. Or write getters and setters for a Rectangle class? That thing is just a bunch of variables, and doesn't need any getters and setters. You're not exactly going to inherit from it, and you can't really change the internal logic and maintain the same semantics, so it's very meaningless to not just make the variables public.
The Rectangle class needs a very healthy dose of YAGNI, and the House class just needs to look at itself again. The fact that there's no intelligence in the "passthrough" methods should be a huge alarm bell telling you that they are quite probably redundant and not helpful- especially since you can't change the public variables without breaking your interface anyway, it's not like the getters and setters are decreasing coupling or anything like that.
Methods should perform logic, or in the very least case, exist where logic might have to be done.