Related
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'm currently working on a little game engine project in C++ using DirectX for rendering. The rendering part of the engine consists of classes such as Model and Texture. Because I would like to keep it (relatively) simple to switch to another rendering library (e.g. OpenGL) (and because I suppose it's just good encapsulation), I would like to keep the public interfaces of these classes completely devoid of any references to DirectX types, i.e. I would like to avoid providing public functions such as ID3D11ShaderResourceView* GetTextureHandle();.
This becomes a problem, however, when a class such as Model requires the internal texture handle used by Texture to carry out its tasks - for instance when actually rendering the model. For simplicity's sake, let's replace DirectX with an arbitrary 3D rendering library that we'll call Lib3D. Here is an example demonstrating the issue I'm facing:
class Texture {
private:
Lib3DTexture mTexture;
public:
Texture(std::string pFileName)
: mTexture(pFileName)
{
}
};
class Model {
private:
Texture* mTexture;
Lib3DModel mModel;
public:
Model(std::string pFileName, Texture* pTexture)
: mTexture(pTexture), mModel(pFileName)
{
}
void Render()
{
mModel.RenderWithTexture( /* how do I get the Lib3DTexture member from Texture? */ );
}
};
Of course, I could provide a public GetTextureHandle function in Texture that simply returns a pointer to mTexture, but this would mean that if I change the underlying rendering library, I would also have to change the type returned by that function, thus changing the public interface of Texture. Worse yet, maybe the new library isn't even structured the same way, meaning I'd have to provide entirely new functions!
The best solution I can think of is making Model a friend of Texture so that it can access Texture's members directly. This seems slightly unwieldy, however, as I add more classes that make use of Texture. I have never used friendship much at all, so I'm not sure if this is even an acceptable usage case.
So, my questions are:
Is declaring Model a friend of Texture an acceptable use of
friendship? Would it be a good solution?
If no, what would you
recommend? Do I need to redesign my class structure
completely? In that case, any tips?
PS: I realize that the title is not very descriptive and I apologize for that, but I didn't really know how to put it.
Whether it is an acceptable use of friendship is debatable. With every feature, even good ones, that you use, you risk that anti-patterns form in your code. So just use it with moderation and be cautious for anti-patterns.
While you can use friendships you can also simply use inheritance i.e. IGLTexture : ITexture and cast to the appropriate interface wherever implementation detail needs to be accessed. For instance IGLTexture could expose everything opengl related.
And there is even another paradigm that could be used. pimpl which stands for
private implementation. In short rather than exposing implementation detail
within the class, you just supply all implementation detail in a class whose implementation is unspecified publicly. I've been using this approach myself with little second regrets.
//header
class Texture
{
int width, height, depth;
struct Impl;
char reserved[32];
*Impl impl;
Texture();
...
};
//cpp
struct Texture::Impl
{
union
{
int myopenglhandle;
void* mydirectxpointer;
};
};
Texture::Texture()
{
impl = new (reserved) Impl();
}
You need to abstract this mo-fo.
class TextureBase{
public:
virtual Pixels* getTexture() = 0;
virtual ~TextureBase(){}
};
class Lib3DTexture: public TextureBase {
private:
Lib3DTexture mTexture;
public:
Texture(std::string pFileName)
: mTexture(pFileName)
{
}
Pixels* getTexture(){ return mTexture.pixels(); }
};
class Renderable{
public:
virtual void render()const = 0;
virtual ~Renderable(){}
};
class ModelBase: public Renderable{
public:
virtual ModelData* getModelData() = 0;
virtual ~ModelBase(){}
};
class Lib3DModel : ModelBase{
private:
TextureBase* texture;
ModelBase* model;
public:
Lib3DModel(std::string pFileName, Texture* pTexture): mTexture(pTexture), mModel(pFileName){}
void render()const{
model.renderWithTexture( texture.getPixels() );
}
};
class World: public Renderable{
private:
std::vector< std::shared_ptr<Renderable> > visibleData;
public:
void render()const{
for_each(visiableData.begin(),visiableData.end(),std::mem_fun(Renderable::render));
}
};
you get the idea, not guaranteeing it compiles but just to give you an idea.Also check out user2384250 comment, good idea as well.
Make Texture a template with a default template parameter using DirectX.
So you can do this:
template<typename UnderlyingType = Lib3DTexture> class Texture {
private:
UnderlyingType mTexture;
public:
Texture(std::string pFileName)
: mTexture(pFileName)
{
}
UnderlyingType UnderlyingTexture(); //returns UnderlyingType, no matter which library you use
};
I think this could be a clean way of solving that problem, and easily allowing the switching out of underlying libraries.
Since the 2 APIs are mutually exclusive and since you probably don't need to switch between the 2 at runtime, I think you should aim at building 2 different executables, one for each of the underlying API.
By that I mean use:
#if OpenGL_implementation
...
#else // DirectX
...
#if
This may or may not be the sexy solution you were looking for. But I believe this is the cleaner and simpler solution. Going with heavy template use (resp. heavy polymorphic behaviour) will probably cause even more code bloat than an #if solution and it will also compile (resp. run) slower as well. :)
In other words, if you can afford to have the 2 behaviours you want in 2 different executables, you should not allow this to have an impact on your software architecture. Just build 2 sexy, twin software solutions instead of 1 fat one. :)
From my experience, using C++ inheritance for those sort of problems often ends a quite complex and unmaintainable project.
There are basically two solutions:
Abstract all data types, making them not depend on the rendering layer at all. You will have to copy some data structures from rendering layer, but you only need to replace rendering code.
Choose a portable render layer (OpenGL) and stick to it.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I have a very big design stumbling block in my rendering code. Basically what this is, is not requiring API specific code (such as OpenGL code or DirectX). Now I've thought of numerous ways on how to solve the problem, however I'm not sure which one to use, or how I should improve upon these ideas.
To give a brief example, I will use a Texture as an example. A texture is an object which represents a texture in GPU memory, implementation wise it may be resembled in any particular way, i.e. whether implementation uses a GLuint or LPDIRECT3DTEXTURE9 to resemble the texture.
Now here are the ways I've thought of to actually implement this. I'm quite unsure if there is a better way, or which way is better than another.
Method 1: Inheritance
I could use inheritance, it seems the most obvious choice for this matter. However, this method requires virtual functions, and would require a TextureFactory class in order to create Texture objects. Which would require calls to new for each Texture object (e.g. renderer->getTextureFactory()->create()).
Here's how I'm thinking of using inheritance in this case:
class Texture
{
public:
virtual ~Texture() {}
// Override-able Methods:
virtual bool load(const Image&, const urect2& subRect);
virtual bool reload(const Image&, const urect2& subRect);
virtual Image getImage() const;
// ... other texture-related methods, such as wrappers for
// load/reload in order to load/reload the whole image
unsigned int getWidth() const;
unsigned int getHeight() const;
unsigned int getDepth() const;
bool is1D() const;
bool is2D() const;
bool is3D() const;
protected:
void setWidth(unsigned int);
void setHeight(unsigned int);
void setDepth(unsigned int);
private:
unsigned int _width, _height, _depth;
};
and then in order for OpenGL (or any other API specific) textures to be created, a sub-class would have to be made, such as OglTexture.
Method 2: Use a 'TextureLoader' or some other class
This method is as simple as it sounds, I use another class to handle loading of textures. This may or may not use virtual functions, depending on the circumstance (or whether I feel it is necessary).
e.g. A polymorphic texture loader
class TextureLoader
{
public:
virtual ~TextureLoader() {}
virtual bool load(Texture* texture, const Image&, const urect2& subRect);
virtual bool reload(Texture* texture, const Image&, const urect2& subRect);
virtual Image getImage(Texture* texture) const;
};
If I were to use this, a Texture object would only be a POD type. However, in order for this to work, a handle object/ID would have to be present within the Texture class.
For example, this is how I would more than likely implement it. Although, I may be able to generalise the whole ID thing, using a base class. Such as a Resource base class in which case holds an ID for a graphics resource.
Method 3: The Pimpl Idiom
I could use the pimpl idiom, which implements how to load/reload/etc. textures. This would more than likely require an abstract factory class for creation of textures. I am unsure how this is better than using inheritance. This pimpl idiom could be used in conjunction with Method 2, i.e. Texture objects would have a reference (pointer) to their loader.
Method 4: Using concepts/compile-time polymorphism
I could on the other hand, use compile-time polymorphism and basically use what I presented in the inheritance method, except without declaring virtual functions. This would work, but if I wanted to dynamically switch from OpenGL rendering to DirectX rendering, this would not be the best solution. I would simply put OpenGL/D3D specific code within the Texture class, where there would be multiple texture classes with some-what the same interface (load/reload/getImage/etc.), wrapped inside some namespace (resembling which API it uses, e.g. ogl, d3d, etc.).
Method 5: Using integers
I could just use integers to store handles to texture objects, this seems fairly simple, but may produce some-what "messy" code.
This problem is also present for other GPU resources such as Geometry, Shaders, and ShaderPrograms.
I've also thought of just making the Renderer class handle the creation, loading, and etc. of graphical resources. However this would violate SPR. e.g.
Texture* texture = renderer->createTexture(Image("something.png"));
Image image = renderer->getImage(texture);
Can someone please guide me, I think I'm thinking too heavily about this. I've tried observing various rendering engines, such as Irrlicht, Ogre3D, and others I have found online. Ogre and Irrlicht use inheritance, however I am unsure that this is the best route to take. As some others just use void*, integers, or just put API specific (mainly OpenGL) code within their classes (e.g. GLuint directly within the Texture class). I really cannot decide which design would be the most appropriate for me.
The platforms I am going to target are:
Windows/Linux/Mac
iOS
Possibly Android
I have considered to just use OpenGL specific code, as OpenGL works for all of those platforms. However, I feel that if I do that I will have to change my code quite a lot if I wish to port to other platforms that cannot use OpenGL, such as the PS3. Any advice on my situation will be greatly appreciated.
Think of it from a high-level point of view. How will your rendering code work with the rest of you game/application model? In other words, how do you plan to create objects in your scene and to what degree of modularity? In my previous work with engines, the end result of a well-designed engine generally has a step-by-step procedure that follows a pattern. For example:
//Components in an engine could be game objects such as sprites, meshes, lights, audio sources etc.
//These resources can be created via component factories for convenience
CRenderComponentFactory* pFactory = GET_COMPONENT_FACTORY(CRenderComponentFactory);
Once a component has been obtained there are usually a variety of overloaded methods you could use to construct the object. Using a sprite as an example, a SpriteComponent could contain everything potentially needed by a sprite in the form of sub-components; like a TextureComponent for instance.
//Create a blank sprite of size 100x100
SpriteComponentPtr pSprite = pFactory->CreateSpriteComponent(Core::CVector2(100, 100));
//Create a sprite from a sprite sheet texture page using the given frame number.
SpriteComponentPtr pSprite = pFactory->CreateSpriteComponent("SpriteSheet", TPAGE_INDEX_SPRITE_SHEET_FRAME_1);
//Create a textured sprite of size 100x50, where `pTexture` is your TextureComponent that you've set-up elsewhere.
SpriteComponentPtr pSprite = pFactory->CreateSpriteComponent(Core::CVector2(100, 50), pTexture);
Then it's simply a matter of adding the object to the scene. This could be done by making an entity, which is simply a generic collection of information that would contain everything needed for scene manipulation; position, orientation, etc. For every entity in your scene, your AddEntity method would add that new entity by default to your render factory, extracting other render-dependent information from sub-components. E.g:
//Put our sprite onto the scene to be drawn
pSprite->SetColour(CColour::YELLOW);
EntityPtr pEntity = CreateEntity(pSprite);
mpScene->AddEntity(pEntity);
What you then have is a nice way of creating objects and a modular way of coding your application without having to reference 'draw' or other render-specific code. A good graphics pipeline should be something along the lines of:
This is a nice resource for rendering engine design (also where the above image is from). Jump to page 21 and read onwards where you'll see in-depth explainations of how scenegraphs operate and general engine design theory.
I don't think there's any one right answer here, but if it were me, I would:
Plan on using only OpenGL to start with.
Keep rendering code separate from other code (that's just good design), but don't try to wrap it in an extra layer of abstraction - just do whatever is most natural for OpenGL.
Figure that if and when I was porting to PS3, I would have a much better grasp of what I need my rendering code to do, so that would be the right time to refactor and pull out a more abstract interface.
I've decided to go for a hybrid approach, with method (2), (3), (5) and possibly (4) in the future.
What I've basically done is:
Every resource has a handle attached to it. This handle describes the object. Each handle has an ID associated with it, which is a simple integer. In order to talk to the GPU with each resource, an interface for each handle is made. This interface is at the moment abstract, but could be done with templates, if I choose to do so in the future. The resource class has a pointer to an interface.
Simply put, a handle describes the actual GPU object, and a resource is just a wrapper over the handle and an interface to connect the handle and the GPU together.
This is what it basically looks like:
// base class for resource handles
struct ResourceHandle
{
typedef unsigned Id;
static const Id NULL_ID = 0;
ResourceHandle() : id(0) {}
bool isNull() const
{ return id != NULL_ID; }
Id id;
};
// base class of a resource
template <typename THandle, typename THandleInterface>
struct Resource
{
typedef THandle Handle;
typedef THandleInterface HandleInterface;
HandleInterface* getInterface() const { return _interface; }
void setInterface(HandleInterface* interface)
{
assert(getHandle().isNull()); // should not work if handle is NOT null
_interface = interface;
}
const Handle& getHandle() const
{ return _handle; }
protected:
typedef Resource<THandle, THandleInterface> Base;
Resource(HandleInterface* interface) : _interface(interface) {}
// refer to this in base classes
Handle _handle;
private:
HandleInterface* _interface;
};
This allows me to extend quite easily, and allows for syntax such as:
Renderer renderer;
// create a texture
Texture texture(renderer);
// load the texture
texture.load(Image("test.png");
Where Texture derives from Resource<TextureHandle, TextureHandleInterface>, and where renderer has the appropriate interface for loading texture handle objects.
I have a short working example of this here.
Hopefully this works, I may choose to redesign it in the future, if so I will update. Criticism would be appreciated.
EDIT:
I have actually changed the way I do this again. The solution I am using is quite similar to the one described above, but here is how it is different:
The API revolves around "backends", these are objects that have a common interface and communicate with a low-level API (e.g. Direct3D or OpenGL).
Handles are no longer integers/IDs. A backend has specific typedef's for each resource handle type (e.g. texture_handle_type, program_handle_type, shader_handle_type).
Resources do not have a base class, and only require one template parameter (a GraphicsBackend). A resource stores a handle and a reference to the graphics backend it belongs to. Then the resource has a user-friendly API and uses the handle and graphics backend common interface to interact with the "actual" resource. i.e. resource objects are basically wrappers of handles that allow for RAII.
A graphics_device object is introduced to allow construction of resources (factory pattern; e.g. device.createTexture() or device.create<my_device_type::texture>(),
For example:
#include <iostream>
#include <string>
#include <utility>
struct Image { std::string id; };
struct ogl_backend
{
typedef unsigned texture_handle_type;
void load(texture_handle_type& texture, const Image& image)
{
std::cout << "loading, " << image.id << '\n';
}
void destroy(texture_handle_type& texture)
{
std::cout << "destroying texture\n";
}
};
template <class GraphicsBackend>
struct texture_gpu_resource
{
typedef GraphicsBackend graphics_backend;
typedef typename GraphicsBackend::texture_handle_type texture_handle;
texture_gpu_resource(graphics_backend& backend)
: _backend(backend)
{
}
~texture_gpu_resource()
{
// should check if it is a valid handle first
_backend.destroy(_handle);
}
void load(const Image& image)
{
_backend.load(_handle, image);
}
const texture_handle& handle() const
{
return _handle;
}
private:
graphics_backend& _backend;
texture_handle _handle;
};
template <typename GraphicBackend>
class graphics_device
{
typedef graphics_device<GraphicBackend> this_type;
public:
typedef texture_gpu_resource<GraphicBackend> texture;
template <typename... Args>
texture createTexture(Args&&... args)
{
return texture{_backend, std::forward(args)...};
}
template <typename Resource, typename... Args>
Resource create(Args&&... args)
{
return Resource{_backend, std::forward(args)...};
}
private:
GraphicBackend _backend;
};
class ogl_graphics_device : public graphics_device<ogl_backend>
{
public:
enum class feature
{
texturing
};
void enableFeature(feature f)
{
std::cout << "enabling feature... " << (int)f << '\n';
}
};
// or...
// typedef graphics_device<ogl_backend> ogl_graphics_device
int main()
{
ogl_graphics_device device;
device.enableFeature(ogl_graphics_device::feature::texturing);
auto texture = device.create<decltype(device)::texture>();
texture.load({"hello"});
return 0;
}
/*
Expected output:
enabling feature... 0
loading, hello
destroying texture
*/
Live demo: http://ideone.com/Y2HqlY
This design is currently being put in use with my library rojo (note: this library is still under heavy development).
I use game state manager (intro, main menu, gameplay etc) from here. However there is one problem. A very minimalistic example:
class cApp //manages the states and gives them access to window
{
public:
cApp (RenderWindow & ref) : window(ref) {}
void changeState(cState *); //these function realy doesn't matter
void update();
void draw();
RenderWindow & window; //the same as in the article, this class not only manages state but gives them access to window etc
private:
std::vector <cState *> states;
}
The state:
class cState
{
public:
cState(cApp * ptr) : app(ptr) {}
virtual void update() = 0;
virtual void draw() = 0;
protected:
cApp * app;
}
So far everything is good. The problem is this is the part of basic framework. So the cApp is only very basic and gives access only to window. However there may be the case where the user wants to use networking in his game. Network engine isn't a part of single state so it must be at the more global (that means, cApp) level.
So the user does:
class cNetworkedApp : public cApp
{
public:
cNetworkedApp(RenderWindow & ref1, NetworkEngine & ref2)
: networking(ref2), cApp(ref1)
NetworkEngine & networking; //initialized in cNetworkedApp constructor
}
class CharacterCreationState : public cState
{
CharacterCreationState(cApp * ptr) : cState(ptr) {}
//implement pure virtual functions
void draw()
{}
void update()
{
//THE PROBLEM
//the state needs to access the network engine so casting is required
cNetworkedApp * ptr = static_cast<cNetworkedApp*>(app))
ptr->networking.sendSomething();
}
}
The only obvious solution is to include everything what may be possible in cApp, however as I said this is a framework. Of course some engines like physics engine or sound engine are things which you put into a state so that's not problem, but things like networking system must be the one object available for all states. And not every app uses it.
Do I need to redesign this code or is it okay?
Your cApp may keep with it a named list of a polymorphic type Engine, ie map<string,Engine*>, then, your user may ask the cApp if it has a given engine.
NetworkEngine would be a subclass of the pure abstract Engine.
Update
When dealing with a pointer that I you are sure that it is of the given specialized type, you should use static_cast, when you wanna query if the pointer can be casted to a type you should use dynamic_cast.
I, myself, have a safer approach for the first case, I use an assertion to guarantee that the type can be casted and use the static_cast in normal code:
Engine* fetchedEngine = cApp.fetch("network");
assert( dynamic_cast<NetworkEngine*>(fetchedEngine) != NULL );
NetworkEngine* network = static_cast<NetWorkEngine*>(fetchedEngine);
Only a object of type NetworkEngine should be putted on the "network" name, but maybe someone mistakenly put something else, the assert will make us safer without needing to worry about the overhead.
I'm not having a lot of luck in C++ getting one of my classes to see/reference/copy data from one of my other classes so it can use it.
Basically I get the error 'Core' does not name a type or when I try to forward declare (http://stackoverflow.com/questions/2133250/does-not-name-a-type-error-in-c) I get field 'core' has incomplete type
I'm guessing the second error is due to the class not really being initialized possibly, so it has nothing to get? I dunno :( (see code at the bottom)
In my C# games I would normally create a "core" class, and then within that I would start other classes such as 'entities', 'player', 'weapons', etc. When I start these other classes I would pass "this"
public WeaponManager c_WeaponManager;
...
c_WeaponManager = new WeaponManager(this);
so I could always access public values of any class from anywhere as long as it passed through core.
Eg:
So when I do my update through the 'weapon' class, and it detects its hit the player, I'd simply get a function within that class to...
core.playerClass.deductHealth(damageAmmount);
..or something like that.
It allowed me to keep lots of variables I wanted to access globally neatly tucked away in areas that I felt were appropriate.
I know this isn't a good method of programming, but its what I'm fairly comfortable with and I mainly do hobby programming so I like being able to access my data quickly without bureaucratic Get() and Set() functions handing data from one class to another and another. Also I'm still fumbling my way through header files as they seem to be a pain in the ass
//-----------[In vid_glinit.h]-------------------
include "core.h"
class Vid_glInit
{
public:
RECT glWindowRect;
Core core;
Vid_glInit();
~Vid_glInit();
void StartGl(HWND _hGameWindow, int resolutionX, int resolutionY);
private:
};
//------------[in core.h]----------
include "vid_glinit.h"
class Core
{
public:
Vid_glInit vid_glinit(this);
enum GAME_MODE
{
INIT,
MENUS,
GAMEPLAY
};
GAME_MODE gameMode;
HWND hGameWindow;
HGLRC hGameRenderContext; // Permanent Rendering Context
HDC hGameDeviceContext; // Private GDI Device Context
//functions go here
Core();
~Core();
void testFunc();
void Run();
void Update();
void Render();
void StartGl(int resoultionX, int resolutionY);
private:
};
The goal is that when I start OpenGl, instead of having lots of little functions to pass data around I simply tell the glFunctions who need the Device or Rendering context to use core.hGameDeviceContext , if that makes sense
The problem is that you've got
class Vid_glInit
{
public:
Core core;
which means allocate a full copy of the Core object inline inside this class, and also
class Core
{
public:
Vid_glInit vid_glinit(this);
which means allocate a full copy of the Vid_glInit object inline inside the class - and this is now circular, and neither structure's size can be computed.
You probably actually want to allocate at least one of them by reference or pointer, i.e.
class Core
{
public:
Vid_glInit* vid_glinit; // pointer: access properties as core.vid_glinit->foo
Vid_glInit& vid_glinit; // reference: properties are core.vid_glinit.foo
In that case you can use the class Vid_glInit; simple forward declaration because these are just pointers internally and the size of a pointer is fixed regardless of the structure behind it, i.e. C++ can lay out the Core class in memory without full knowledge of the Vid_glInit structure.