I'm currently creating a game in SFML. To put it simply, I have an Object class that has all the common features for all objects. Player and Enemy class inherit from Object. There is also an ObjectManager that has a list of all Object and updates and draws them etc.
// using SFML shapes
class Player : public Object
{
public:
sf::CircleShape playerShape;
};
class Enemy : public Object
{
public:
sf::Sprite enemyShape;
};
class Object
{
public:
void move(...) { // move the shape, but the shapes are only found in the derived }
void draw(...) { // same problem as above, etc... }
};
class ObjectManager
{
private:
std::map<int, std::shared_ptr<Object>> gameObjectMap; // id, object
public:
void updateAll(...) {
// loop over all objects and update them
for (auto itr = gameObjectMap.begin(); itr != gameObjectMap.end(); ++itr) {
itr->second->move(...);
itr->second->draw(...);
}
}
};
Above you can see that Object::move() cannot be used because Object does not know about the SFML shapes in the derived classes. Therefore you could make the function Object::move() pure virtual but this means that you'd need to write implementations in the derived classes for any shape specific function that you need to use, this also includes any attributes about the shape, such as its position sf::Shape::getPosition(), etc. So this approach does not scale well.
An alternative that I thought about would be to have the Object class as a class template
template<typename T>
class Object
{
protected:
T object;
public:
void move(...) { object.move(...); }
T getObject() { return object; }
};
class Player : public Object<sf::CircleShape>
{ ... };
However this means that ObjectManager now must hold class templates Object in the map, and I'm not sure how that would work?
What's the best way to handle this situation?
how about this:
class Object
{
virtual auto move() -> void = 0;
};
template <class Shape>
class Shape_object : Object
{
Shape shape;
auto move() -> void override
{
// implementation
}
};
// you can have specializations for each shape type
// if you can't use the generic one
class Player : public Shape_object<sf::CircleShape>
{
//
};
class Enemy : public Shape_object<sf::Sprite>
{
//
};
template<typename T>
class Object {
// ...
};
If you really consider using a template class, you should use the CRTP (aka Static Polymorphism):
template<typename Derived>
class Object {
public:
/* virtual */ auto move() -> void {
// ^^^^^^^^^^^^^ Hooray! No more vtable \o/ (but wait ...)
static_cast<Derived*>(this)->doMove(); // Fails to compile, if
// Derived isn't inheriting from
// Object<Derived> or Derived
// doesn't implement doMove().
};
};
The drawback of that pattern is that everything must be resolved at compile time. Runtime injections of interface implementations (e.g. via plugins) won't work with that pattern well.
You could leave a thin layer though to make virtual destruction and such work properly:
struct ObjectBase {
virtual ~ObjectBase() {} // << that's enough
};
template<typename Derived>
class Object : public ObjectBase {
// ...
}
Related
I am trying to implement the curiously recurring template pattern (CRTP) to access a member variable of a child class from the parent class, but I am getting a compilation error saying I am illegally referencing a non-static member variable.
#include <iostream>
template <typename Child>
class Parent
{
public:
int get_value()
{
return Child::m_value;
}
virtual ~Parent() = default;
};
class Child : public Parent<Child>
{
int m_value = 42;
friend class Parent<Child>;
};
int main()
{
Child child;
std::cout << child.get_value() << std::endl;
}
Error:
illegal reference to non-static member 'Child::m_value'
How can I properly access the member variable of the child class from within the parent class?
Is CRTP even the best/cleanest approach here?
Here is the correct way to access members of a CRTP derived class.
template <typename Child>
class Parent
{
public:
int get_value()
{
// Do NOT use dynamic_cast<> here.
return static_cast<Child*>(this)->m_value;
}
~Parent() { /*...*/ }; // Note: a virtual destructor is not necessary,
// in any case, this is not the place to
// define it.
};
// A virtual destructor is not needed, unless you are planning to derive
// from ConcreteClass.
class ConcreteClass : public Parent<ConcreteClass>
{
friend class Parent<ConcreteClass>; // Needed if Parent needs access to
// private members of ConcreteClass
// If you plan to derive from ConcreteClass, this is where you need to declare
// the destructor as virtual. There is no ambiguity as to the base of
// ConcreteClass, so the static destructor of Parent<ConcreteClass> will
// always be called by the compiler when destoying a ConcreteClass object.
//
// Again: a virtual destructor at this stage is optional, and depends on
// your future plans for ConcreteClass.
public:
virtual ~ConcreteClass() {};
private:
int m_value;
};
// only ConcreteClass needs (optionally) a virtual destructor, and
// that's because your application will deal with ConcretClass objects
// and pointers, for example, the class below is totally unrelated to
// ConcreteClass, and no type-safe casting between the two is possible.
class SomeOtherClass : Parent<SomeOtherClass> { /* ... */ }
ConcreteClass obj1;
// The assignment below is no good, and leads to UB.
SomeOtherClass* p = reinterpret_cast<ConcreteClass*>(&obj1);
// This is also not possible, because the static_cast from
// Parent<UnrelatedClass>* to UnrelatedClass* will not compile.
// So, to keep your sanity, your application should never
// declare pointers to Parent<T>, hence there is never any
// need for a virtual destructor in Parent<>
class UnrelatedClass {/* ... */ };
auto obj2 = Parent<UnrelatedClass>{};
As the concrete type ConcreteClass and its relation to Parent is known ate compile-time, a static_cast is sufficient to convert this from Parent<ConcreteClass>* to a ConcreteClass*. This provides the same functionality as virtual functions without the overhead of a virtual function table, and indirect function calls.
[edit]
Just to be clear:
template <typename Child>
class Parent
{
public:
int get_value()
{
// the static cast below can compile if and only if
// Child and Parent<Child> are related. In the current
// scope, that's possible if and only if Parent<Child>
// is a base of Child, aka that the class aliased by Child
// was declared as:
// class X : public Parent<X> {};
//
// Note that it is important that the relation is declared
// as public, or static_cast<Child*>(this) will not compile.
//
// The static_cast<> will work correctly, even in the case of
// multiple inheritance. example:
//
// class A {];
// class B {};
// class C : public A
// , public Parent<C>
// , B
// {
// friend class Parent<C>;
// int m_value;
// };
//
// Will compile and run just fine.
return static_cast<Child*>(this)->m_value;
}
};
[edit]
If your class hierarchy gets a bit more complex, the dispatching of functions will look like this:
template <typename T>
class A
{
public:
int get_value()
{
return static_cast<T*>(this)->get_value_impl();
}
int get_area()
{
return static_cast<T*>(this)->get_area_impl();
}
};
template <typename T>
class B : public A<T>
{
friend A<T>;
protected:
int get_value_impl()
{
return value_;
}
int get_area_impl()
{
return value_ * value_;
}
private:
int value_;
};
template <typename T>
class C : public B<T>
{
// you must declare all bases in the hierarchy as friends.
friend A<T>;
friend B<T>;
protected:
// here, a call to C<T>::get_value_impl()
// will effetively call B<T>::get_value_impl(),
// as per usual rules.
// if you need to call functions from B, use the usual
// syntax
int get_area_impl()
{
return 2 * B<T>::get_value_impl();
}
};
Well, i have next code:
#include <type_traits>
#include <iostream>
#include <string>
#include <list>
#include <functional>
class base_main
{
public:
virtual ~base_main()
{
}
// some methods
};
class base_1 : virtual public base_main
{
// some methods
};
class base_2 : virtual public base_main
{
// some methods
};
class base_3 : virtual public base_main
{
// some methods
};
class object : public base_1, public base_2, public base_3
{
// some methods
};
// in other *hpp file
class object_controller_listener
{
public:
virtual void object_created( base_main* o )
{
// well, i want to work only with base_1 and base_2 interfaces, but not with base_3, and also i don't want to know something about object class in this *hpp
// is it good code design?
auto* xxx = dynamic_cast<base_1*>( o );
}
};
class objects_controller
{
void create()
{
std::unique_ptr<object> obj;
// ...
for( auto listener : m_listeners )
listener->object_created( obj.get() );
}
std::list<object_controller_listener*> m_listeners;
};
int main()
{
}
The question is - how can i work only with base_1 and base_2 interfaces? Should i create two separate listeners for them, and send two events in create() function, or should i use dynamic_cast for downcasting and send only one event in create() function? Is this good code design or is this feels like code smell?
UPD:
For example: base_1 - is render_base class, which contains render data, and have functions for set and get this data base_2 - collider base class which contains collider data, and have functions for set and get this data base_3 is physic base class and object is inheritance of all this classes. And when i want work only with render class i use create event which send only render_base class to the render_system, which works only with renders objects and truly use polymorphism. But if i want in some other place work with collider and physic objects, without knowledge about render - how can i use polymorphism here in base classes?
It is hard to tell what design you should choose as this heavily depends on the overall structure of the application.
Generally, I would avoid having a function with the signature virtual void object_created( base_main* o ) in which you dynamically cast to base_* and work on that directly in this function. Because the function signature is part of the documentation of the API.
So I would create distinct functions for base_1 and base_2 and call those.
How to do that depends again on the overall structure. You could create a helper function, that forwards the call to the other functions (this is just a fast implementation how that could look like:
template <typename DestT, typename SrcT, typename T>
void forward_if(SrcT obj, T *o, void (T::*f)(DestT)) noexcept {
if (auto tmp = dynamic_cast<DestT>(obj); tmp != nullptr) {
(o->*f)(tmp);
}
}
And then you could use it like this:
#include <iostream>
#include <vector>
class base_main {
public:
virtual ~base_main() {}
};
class base_1 : virtual public base_main {};
class base_2 : virtual public base_main {};
class base_3 : virtual public base_main {};
class object : public base_1, public base_2, public base_3 {};
template <typename DestT, typename SrcT, typename T>
void forward_if(SrcT obj, T *o, void (T::*f)(DestT)) noexcept {
if (auto tmp = dynamic_cast<DestT>(obj); tmp != nullptr) {
(o->*f)(tmp);
}
}
struct listener_base {
virtual void object_created(base_main *o) = 0;
};
struct specific_listener : public listener_base {
void object_created(base_main *o) override {
forward_if<base_1 *>(o, this, &specific_listener::object_created);
forward_if<base_2 *>(o, this, &specific_listener::object_created);
}
void object_created(base_1 *o) {
std::cout << "object created base_1" << std::endl;
}
void object_created(base_2 *o) {
std::cout << "object created base_2" << std::endl;
}
};
int main() {
std::vector<listener_base *> listeners;
listeners.push_back(new specific_listener());
object o;
for (auto listener : listeners) {
listener->object_created(&o);
}
return 0;
}
I have a sprite class, which has a templatised data member. It holds an object, which has a pointer to this specialised sprite template class.
That object requires a forward declaration of my sprite class, but since sprite is a template class, I need to include the full header. Therefore I get a cyclic dependancy which I am unable to figure out
Sprite.h
#include "myclass.h"
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<SpriteType>;
Sprite() {
}
auto foo() {
return s;
}
private:
};
myclass.h
#include "Sprite.h"
//a sprite of type T, is going to create a myclass<Sprite<T>>, a pointer of the Sprite<T> is held in myclass.
template<typename T>
class myclass
{
public:
std::shared_ptr<Sprite<T>> ptr;
myclass() {
}
private:
};
How could I solve this cyclic dependency?
So in summary:
-Sprite is a template class.
-Sprite holds an object to another class. This other class holds a pointer to my this templated sprite class.
-This gives me a cyclic dependency, since both classes are now templates, and need to have their implementations written in their header files.
Simplified decoupling, based on #Taekahns solution.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
// DO NOT PASS SpriteType here, put the whole Sprite<SpriteType>
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
One of the great thing about templates is breaking type dependencies.
You could do something like this. Simplified for readability.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = std::enable_if_t<std::is_base_of_v<base_class, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
That is one of many options.
Another option is to use an interface. i.e. a pure virtual base class that isn't a template.
Example:
I think something like this should do it. Starting to get a hard to follow though.
class base_sprite
{
public:
virtual ~base_sprite(){};
virtual int foo() = 0;
};
template<typename T>
class myclass
{
public:
std::shared_ptr<base_sprite> ptr;
myclass() : ptr(std::make_shared<T>())
{
};
};
template<typename SpriteType>
class Sprite : public base_sprite{
public:
myclass<Sprite<SpriteType>> l;
int foo() override {return 0;};
};
I have programmed several windows for an application that all inherit Gtkmm::Window. At this point, I would like to automate the process. Right now, the following structure stands out:
class MyWindow : public Gtk::Window
{
public:
MyWindow();
virtual ~MyWindow();
//...
private:
void registerLayouts(); // Adds layouts to the window.
void registerWidgets(); // Adds widgets to the layouts.
//...
};
And the constructor:
MyWindow::MyWindow()
{
registerLayouts(); // Cannot be virtual: in constructor.
registerWidgets(); // Cannot be virtual: in constructor.
//...
}
So the problem is that all of this has to be done manually (i.e. copy/pasted) every time a new window has to be programmed because registerLayouts() and registerWidgets() are called at construction and hence cannot be virtual.
Ideally, I would have a base class that I could inherit from which would give me the option of overriding the two methods and would take care of the rest: it would call the two methods at an appropriate location.
The thing is, I have not found where this appropriate location could be. I have look at different signal handlers, but there seem to be none for this.
Do you have an idea of how I could do this?
MFC has the CDialog::OnInitDialog() that performs something similar to what I need.
You could delegate the work to a separate class:
class MyWindow : public Gtk::Window
{
//public: *** EDIT ***
protected:
template <typename LayoutManager>
MyWindow(LayoutManager const& lm)
{
lm.registerLayouts(this);
lm.registerWidgets(this);
}
};
class SubWindow : public MyWindow
{
class LM { /* ... */ };
public:
SubWindow() : MyWindow(LM()) { }
};
(Edited: The improved pattern hides away from public the layout managers of sub classes...)
Alternatively, the whole class as template (possibly superior to above):
template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
public:
MyWindow()
{
LayoutManager lm(*this);
lm.registerLayouts();
lm.registerWidgets();
}
};
class SpecificLayoutManager { /* ... */ };
using SpecificWindow = MyWindow<SpecificLayoutManager>;
If you need the layout manager for cleaning up as well (not familiar with GTK myself...):
template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
LayoutManager lm;
public:
MyWindow() : lm(*this)
{
lm.registerLayouts();
lm.registerWidgets();
}
virtual ~MyWindow()
{
// still access to lm...
}
};
Important side note: In all variants we do not yet have a fully constructed derived class – casting to the latter within the layout managers thus is not legal (experimented with curiously recurring template pattern, but dropped the idea for exactly the same reason: needed to cast to derived in constructor of base as well).
Edit in response to comments: A sample on how you could manage additional members of a subclass (using third variant above, the template class one with the layout manager member; lm member now needs to be protected):
class SubWindowLayoutManager
{
template <typename>
friend class MyWindow;
friend class SubWindow;
int someMember;
void registerLayouts() { }
void registerWidgets() { }
};
class SubWindow : public MyWindow<SubWindowLayoutManager>
{
void doSomething()
{
lm.someMember = 77;
}
};
Additionally a new variant entirely without templates:
class MyWindow : public Gtk::Window
{
protected:
class LayoutManager
{
public:
virtual void registerLayouts(MyWindow* parent) = 0;
virtual void registerWidgets(MyWindow* parent) = 0;
};
std::unique_ptr<LayoutManager> lm;
MyWindow(std::unique_ptr<LayoutManager> lm)
: lm(std::move(lm))
{
this->lm->registerLayouts(this);
this->lm->registerWidgets(this);
}
};
class SubWindow : public MyWindow
{
class LM : public LayoutManager
{
public:
void registerLayouts(MyWindow* parent) override { }
void registerWidgets(MyWindow* parent) override { }
int someMember;
};
// convenience access function:
inline LM& lm()
{
return *static_cast<LM*>(MyWindow::lm.get());
}
public:
SubWindow() : MyWindow(std::make_unique<LM>()) { }
void doSomething()
{
//static_cast<LM*>(lm.get())->someMember = 77;
lm().someMember = 77;
}
};
I'm looking for a clean way of doing this since a long time. In my problem, there exist 3 classes not sharing any parent in common but each having some methods with the same name (A.doSomething, B.doSomething, C.doSomething). Hence, having the same function signature, class D inheriting from A and using method doSomething() will "look the same" to E inheriting from B or C .
Here is a sketch of what I'd like to be able to do:
class Base {
public:
void myMethod(void) { doSomething(); }
};
class Independent {
public:
doSomething();
};
clase Derived : public Base : public Independent {
(...)
};
int main(void) {
Derived *derivedObject = new Derived();
derivedObject->myMethod();
}
In this problem, object of type "Independent" is provided by a library that I cannot change. I would like to define a base class that uses methods that are going to be inherited later on. I couldn't find a proper way of doing this using virtual inheritance without causing ambiguous compiling.
You've got a nasty situation there. One solution to this would be using the Curiously Recurring Template Pattern to perform the inheritance at compile-time, like this:
template <typename D>
class Base {
public:
void myMethod(void) { static_cast<D*>(this)->doSomething(); }
};
class Independent {
public:
void doSomething();
};
clase Derived : public Base : public Independent {
/*...*/
};
int main(void) {
Derived *derivedObject = new Derived();
derivedObject->myMethod();
}
Alternatively, you could choose to put a middleman class in between to forward to Independent (I assume you have many classes deriving from the same Base and Independent, and just don't want to have to do this for each class).
template <typename D>
class Base {
private:
virtual void doSomethingImpl();
public:
void myMethod(void) { doSomethingImpl(); }
};
class Independent {
public:
void doSomething();
};
class IndependentWrapper : public Base : public Independent {
private:
void doSomethingImpl() { Independent::doSomething(); }
};
clase Derived : public IndependentWrapper {
/*...*/
};
int main(void) {
Derived *derivedObject = new Derived();
derivedObject->myMethod();
}