I'm not very good at C++ (but I'm familiar with OOP/Java), but I have to create a game for my C++ class. I want to setup a kind of game engine like that used for Flash games written in ActionScript.
I wrote this two classes, where Actor is meant as a base class (probably will be abstract) and Player should actually implement it.
The problem is that I want to avoid duplicate code in the functions addEventListener and handle and re-declaring _handlerMap, since I want to achieve data hiding and such things.
The problem, I guess, is that _eventMap should contain handler values that can change class Actor::*handler and Player::*handler. Is it possible?
class Actor {
protected:
typedef void(Actor::*handler)(Event);
map<int, handler> _handlerMap;
public:
virtual void addEventListener(int ID, handler h) {
_handlerMap.insert(std::make_pair(ID, h));
};
virtual void handle(int ID) {
handler h = _handlerMap[ID];
Event e;
if (h)
(this->*h)(e);
}
virtual void onUpdate(Event e) {
cout << "Actor::onUpdate()" << endl;
};
};
class Player : public Actor {
typedef void(Player::*handler)(Event);
map<int, handler> _handlerMap;
public:
void addEventListener(int ID, handler h) {
_handlerMap.insert(std::make_pair(ID, h));
};
void handle(int ID) {
handler h = _handlerMap[ID];
Event e;
if (h)
(this->*h)(e);
}
void onKeydown(Event e) {
cout << "Player::onKeyDown()" << endl;
};
};
I wish it was possible to declare Player as:
class Player : public Actor {
typedef void(Player::*handler)(Event);
public:
void onWhateverEvent(Event e);
}
I hope you understand.
You need something like this (not tested):
class Dispatcher {
public:
virtual void dispatchEvent(Event*) = 0;
};
template <class C>
class DispatcherImpl : public Dispatcher
{
typedef void(C::*handler)(Event* e);
std::map<int, handler> _handlerMap;
C* _owner;
public:
DispatcherImpl (C* c) : _owner(c) {}
addEventListener(int ID, handler h) {
_handlerMap.insert(std::make_pair(ID, h));
}
void dispatchEvent(Event*)
{
handler h = handlerMap[e->id];
if (h) (_owner->*h)(e);
}
}
Now let each type T of actor own a DispatcherImpl<T>, and you are all set. You may also have e.g. Player inherit from DispatcherImpl<Player>.
What do you think of this? (Dispatcher is the same as DispatcherImpl above)
template <class T>
class Entity {
T *_instance;
Dispatcher<T> *_dispatcher;
public:
Entity() {
_instance = new T();
_dispatcher = new Dispatcher<T>(_instance);
}
};
class Actor {
//attirbutes and methods
};
class Player : public Actor {
//attirbutes and methods
};
To use it just:
Entity<Actor> *actor = new Entity<Actor>();
Entity<Player> *player = new Entity<Player>();
actor->getDispatcher()->addEventListener(0, &Actor::foo);
player->getDispatcher()->addEventListener(1, &Player::bar);
player->getDispatcher()->addEventListener(0, &Actor::foo); //inheritance
Related
I have this map:
map<IEvent, EventHandler, IEventCompare>
Where EventHandler is defined as typedef void (*EventHandler)(IEvent);
IEvent is a class that describes a general event.
Now I want to add to this map a function that receives CreationEvent, a class that inherits IEvent. The function is defined so:
void onCreate(CreationEvent);
But when I try to add it to the map, I get a compilation error
E0167 argument of type "void (Engine::IObject::*)(Engine::CreationEvent)" is incompatible with parameter of type "Engine::EventHandler"
And if I try to explicitly convert it to EventHandler:
E0171 invalid type conversion
I can declare onCreate with IEvent, but I would like to avoid it since it will require me to assume the type of event, and it is not well defined.
Is there a way to do what I try?
IEvent:
/**
* Represents an Event, such as collision between 2 objects or click on an object.
*/
class IEvent
{
public:
IEvent(string name) { this->name = name; };
/**
* Copy constructor.
*/
IEvent(const IEvent& other) { this->name = other.name;};
string getName() const { return this->name; };
protected:
string name;
};
CreationEvent:
class CreationEvent : public IEvent
{
public:
CreationEvent();
std::chrono::time_point<std::chrono::system_clock> getCreateTime() const;
private:
std::chrono::time_point<std::chrono::system_clock> creationTime; /**< The creation time of this event.*/
};
Notes:
Everything is inside namespace Engine, and the map is declared inside IObject.
If I get your idea right, you want:
Have typed events with base event class.
Have handlers with base handler class.
Handlers can receive event of certain type.
Consider the next example. For the simplicity I used std::vector instead of std::map, and put it inside event class.
This code contains ugliness, leaks and must not be used in a "production" without modifications.
#include <iostream>
#include <vector>
//***********************************************************//
struct event;
struct handler
{
};
struct event_handler
{
event_handler(handler* receiver) : receiver_{ receiver } {}
handler* receiver_;
virtual void invoke(event& evt) = 0;
};
template <typename T, typename U>
struct event_handler_impl : event_handler
{
typedef void (T::* handler_function)(U&);
event_handler_impl(handler* receiver, handler_function function) :
event_handler{ receiver_ },
function_{ function } {}
void invoke(event& evt) {
T* typed_receiver = static_cast<T*>(receiver_);
U& typed_event = static_cast<U&>(evt);
(typed_receiver->*function_)(typed_event);
}
handler_function function_;
};
struct event
{
void subscribe(event_handler* hdlr)
{
//TODO: Check. Is double added?
handlers_.push_back(hdlr);
}
void sent()
{
for (auto& item : handlers_)
{
item->invoke(*this);
}
}
std::vector<event_handler*> handlers_;
};
//*****************************EXAMPLE***********************//
struct creation_event : public event
{
int creation_id{};
};
struct bar_handler : public handler
{
void handle_creation(creation_event& evt)
{
std::cout << "bar" << evt.creation_id << std::endl;
}
};
struct foo_handler : public handler
{
void handle_creation(creation_event& evt)
{
std::cout << "foo" << evt.creation_id << std::endl;
}
};
template<typename T, typename U>
void subscribe_to_event(U& evt, T* reciver, void (T::* handler_function)(U&))
{
evt.subscribe(new event_handler_impl<T, U>(reciver, handler_function));
}
int main()
{
creation_event evt;
bar_handler bar;
foo_handler foo;
subscribe_to_event(evt, &foo, &foo_handler::handle_creation);
subscribe_to_event(evt, &bar, &bar_handler::handle_creation);
evt.sent();
evt.creation_id = 1;
evt.sent();
return 0;
}
The only tricky part is:
template <typename T, typename U>
struct event_handler_impl : event_handler
Here we generating classes for storing our typed “callback” and using polymorphism to store those classes inside our std::vector since they are all child classes for handler.
As a suggestion - consider using smart pointers instead of raw pointers. Also you can put function void subscribe_to_even(…) to the handler base class, so you can remove second parameter and just pass "this" to the event_handler_impl - new event_handler_impl<T, U>(this, handler_function)
I am trying to implement update which will update to all the listerner classes
I am using class variable to count number of listeners.
MyClass 's are extending listener to listen from the updater class
I am getting runtime error when I am trying to update class variable with class function from member function. Please refer below code and help me out sorting this problem
#define MAX_LISTNERS 10
class Listner{
public:
virtual void onUpdate() = 0;
};
class Updater {
Listner* ptrListner[MAX_LISTNERS];
static int count;
public:
static void updateCount(){
count++;
}
void registerListner(Listner* ptrListner){
this->ptrListner[count] = ptrListner;
this->updateCount(); //---> Runtime Error
}
void updateToListner(){
for(int i=0;i<=count;i++){
this->ptrListner[i]->onUpdate();
}
}
};
int Updater::count = 0;
class MyClass: public Listner{
public:
void onUpdate(){
cout<<"update from MyClass";
}
};
class MyClass2: public Listner{
public:
void onUpdate(){
cout<<"update from MyClass2";
}};
int main() {
MyClass* obj = new MyClass();
MyClass2* obj2 = new MyClass2();
Updater obj_updater;
obj_updater.registerListner(dynamic_cast<Listner*>(obj));
obj_updater.registerListner(dynamic_cast<Listner*>(obj2));
obj_updater.updateToListner();
}
A few things to consider here as this seems all a bit unsafe and not up to the modern C++11 way.
Use RAII for your allocations, i.e. unique_ptr instead of explicit new/delete
Use std::vector instead of a C-Style array declaration. You can limit the amount during runtime. This also gives you implicit listener count
Let the Updater class take care of allocation, factory style which also allows you to respect type safety
Something like the following:
class Listner
{
public:
virtual void onUpdate() = 0;
};
class Updater
{
using ListnerPtr = std::unique_ptr<Listner>;
using Listners = std::vector<ListnerPtr>;
Listners m_listeners;
public:
template < typename T >
bool registerListner()
{
static_assert(std::is_base_of<Listner, T>::value, "T must be derived from Listner");
if (m_listeners.size() >= 10)
return false;
m_listeners.emplace_back(std::make_unique<T>());
return true;
}
void updateToListner()
{
std::for_each(m_listeners.begin(), m_listeners.end(), [](const Listners::value_type& item)
{
item->onUpdate();
});
}
};
class MyClass : public Listner
{
public:
void onUpdate() override
{
std::cout << "update from MyClass" << std::endl;
}
};
class MyClass2 : public Listner
{
public:
void onUpdate() override
{
std::cout << "update from MyClass2" << std::endl;
}
};
int main
{
Updater obj_updater;
obj_updater.registerListner<MyClass>();
obj_updater.registerListner<MyClass2>();
obj_updater.updateToListner();
return 0
}
I am implementing a decorator pattern following the example in here:
Class I: is the interface class, common to both core class and decorator base class
Class A: is the core class
Class D: is the decorator base class
Classes X, Y, Z: inherit from the decorator base class and extend functionality of the core class dynamically
There is one method in class A (A::endTraining()), which is triggered at the end of a timer variable (also present in class A). This method needs to call some member of X, Y and Z classes.
Is it possible? Is it good practice? How?
For example, is creating a mechanism to register the pointers-to-XYZ::endTraining in class A a correct approach?
(showing only relevant bits)
typedef void (D::*pCallback_fn)(void);
class I
{
public:
virtual void endTraining() = 0;
virtual void regTrainingCallbacks(pCallback_fn ptrFn) = 0;
};
class A: public I {
public:
void endTraining() {
//do stuff
//then do stuff in D (and its derivatives)
// by iterating through fnList
}
void regTrainingCallbacks(pCallback_fn ptrFn)
{
fnList.push_back( ptrFn );
}
private:
std::list<pCallback_fn> fnList;
};
class D: public I {
public:
D(I *inner) {
m_wrappee = inner;
}
void regTrainingCallbacks(pCallback_fn ptrFn)
{
m_wrappee->regTrainingCallbacks(ptrFn);
}
private:
I *m_wrappee;
};
class X /*,Y,Z*/ : public D {
public:
X(I *core): D(core)
{
D::regTrainingCallbacks( this->*endTraining() ); //
}
private:
void endTraining(){
//do stuff when called by A::endTraining() through D
}
};
What can be done instead?
Addressing one fault in the original design, in which the 'trainer' (the entity registering training callbacks) must be a callback in itself (is there any reason the notifier - former class A - must be a callback itself?).
I changed the class names to put into evidence their responsibilities.
The MainTrainingProcess replaces the original class A (instances of which would have been wrapped by D-es) and the D itself.
class EndTrainingListener
{
public:
virtual ~EndTrainingListener() { }
virtual void endTraining()=0;
};
class ITrainingProcess
{
public:
virtual ~ITrainingProcess() { }
virtual void regTrainingCallbacks(EndTrainingListener* callback) = 0;
};
class MainTrainingProcess : public ITrainingProcess {
public:
virtual ~MainTrainingProcess() {
// destroy other resources used during training
}
virtual void regTrainingCallbacks(EndTrainingListener* callback) {
this->listeners.push_back(callback);
}
void train() {
// do training stuff
// ...
// do my specific actions at the end of training
// ...
// finish by notifying all listeners
this->atEndTraining();
}
protected:
void atEndTraining() {
for(auto l : this->listeners) {
l->endTraining();
}
}
std::list<EndTrainingListener*> listeners;
};
class X /*Y, Z*/ : public EndTrainingListener {
public:
virtual ~X();
virtual void endTraining() {
// do specific stuff
}
};
In a nutshell, I want to use a single interface, IProducer, to create an object, IProduct. IProduct will have different components depending on which interface created it. The IProduct class will then be used by the IConsumer interface. The correct IConsumer class should be used (I do not want to do type checking myself) based on the derived type of IProduct.
I would essentially like to use the Strategy pattern (different behaviors behind a single interface), but with the added ability to return an object specific to the derived interface used. I want to abide by the Open/Close principle and not alter any of these existing classes when more functionality is added.
I would like to accomplish something like this (I'm sure the syntax is wrong somewhere but bear with me):
class IProduct {
public:
int intData;
};
class ProductA : public IProduct {
public:
float floatData;
};
class ProductB : public IProduct {
public:
bool boolData;
};
class IProducer {
public:
virtual IProduct* produce(void) = 0;
};
class ProducerA : public IProducer {
public:
IProduct* produce(void) {
return new ProductA;
}
};
class ProducerB : public IProducer {
public:
IProduct* produce(void) {
return new ProductB;
}
};
class IConsumer {
public:
virtual void consume(IProduct* prod) = 0;
};
class ConsumerA : public IConsumer {
public:
void consume(IProduct* prod) {
//I want to access the float!
}
};
class ConsumerB : public IConsumer {
public:
void consume(IProduct* prod) {
//I want to access the bool!
}
};
void main() {
IProducer* producer = ProducerFactory::create("ProducerA");
IProduct* product = producer->produce();
IConsumer* consumer = ConsumerFactory::create("ConsumerA");
consumer->consume(product); //I would like the correct consumer to be used here to deal with the ProductA class
}
If you think there is a better way to go about this I'm all ears. Thanks for your help!
What you need is a registry which maps IProduct implementations to the right IConsumer implementations. Basically its just an abstraction of a map:
class ConsumerRegistry
{
std::map<size_t, std::shared_ptr<IConsumer>> m_consumers;
public:
// we are not responsible for products, so lets allow plain ptrs here for more flexibility and less overhead
std::shared_ptr<IConsumer> GetConsumer(IProduct* product)
{
auto it = m_consumers.find(typeid(product).hash_code());
if (it == m_consumers.end())
return nullptr;
else
return it->second;
}
template<typename P>
void RegisterConsumer(std::shared_ptr<IConsumer> consumer)
{
m_consumers.emplace(typeid(P).hash_code(), consumer);
}
template<typename P>
void UnregisterConsumer()
{
m_consumers.erase(typeid(P).hash_code());
}
};
Either expose this class globally (e.g as singleton) or use it in the contexts where you need it. You register consumers like this:
reg.RegisterConsumer<ProductA>(new ConsumerA());
reg.RegisterConsumer<ProductB>(new ConsumerB());
We could also have a virtual void Register(ConsumerRegistry& reg) = 0; method inside IConsumer allowing for safer registering:
void ConsumerA::Register(ConsumerRegistry& reg, std::shared_ptr<IConsumer> self)
{
IConsumer::Register<ProductA>(reg, self);
}
// Required for friendship, can be static:
template<typename T>
void IConsumer::Register(ConsumerRegistry& reg, std::shared_ptr<IConsumer> self)
{
reg->RegisterConsumer<T>(self);
}
void ConsumberRegistry::RegisterConsumer(std::shared_ptr<IConsumer> consumer)
{
consumer->Register(*this, consumer);
}
Make both Register() and the low-level RegisterConsumer() methods private and let ConsumerRegistry and IConsumer be friends. Can be used like this then:
reg.RegisterConsumer(new ConsumerA());
reg.RegisterConsumer(new ConsumerB());
This is a solution I'm thinking of using. I'd appreciate any feedback.
I'm going to use the Visitor pattern and introduce the ProductVisitor class like so:
class IProductVisitor {
public:
explicit IProductVisitor() {}
virtual ~IProductVisitor(){}
virtual void visitA(ProductA* model) = 0;
virtual void visitB(ProductB* model) = 0;
};
class ProductTypeVisitor : public IProductVisitor {
public:
typedef enum {Unknown, A, B} ProductType;
explicit ProductTypeVisitor() : modelType(Unknown) {}
virtual ~ProductTypeVisitor(){}
virtual void visitA(ProductA* product) {
modelType = A;
}
virtual void visitB(ProductB* product) {
modelType = B;
}
ProductType getProductType(void) {
return modelType;
}
ProductType modelType;
};
class IProduct {
public:
IProduct() : intData(3) {}
virtual ~IProduct(){}
int intData;
virtual void accept(IProductVisitor* v) = 0;
};
class ProductA : public IProduct {
public:
ProductA() : IProduct(), floatData(5.5) { }
virtual ~ProductA(){}
float floatData;
void accept(IProductVisitor* v) {
v->visitA(this);
}
};
class ProductB : public IProduct {
public:
ProductB() : IProduct(),boolData(false) { }
virtual ~ProductB(){}
bool boolData;
void accept(IProductVisitor* v) {
v->visitB(this);
}
};
When making my factory, ConsumerFactor, I will use the ProductTypeVisitor class to determine what class the product is, dynamically cast it correctly (based off of the state of the enum), and then return a consumer initialized with the correct product.
class ConsumerFactory {
public:
explicit ConsumerFactory(void) {}
IConsumer* createFromProduct(IProduct* product) {
ProductTypeVisitor visitor;
product->accept(&visitor);
ProductTypeVisitor::ProductType productType = visitor.getProductType();
IConsumer* consumerPtr;
switch (productType) {
case ProductTypeVisitor::A :
consumerPtr = new ConsumerA(dynamic_cast<ProductA*>(product));
break;
case ProductTypeVisitor::B :
consumerPtr = new ConsumerB(dynamic_cast<ProductB*>(product));
break;
default:
std::cout << "Product type undefined. (throw exception)" << std::endl;
break;
}
return consumerPtr;
}
private:
ProductTypeVisitor visitor;
};
Finally, the code will look like this:
IProducer* producer = new ProducerA;
IProduct* product = producer->produce();
ConsumerFactory factory;
IConsumer* consumer = factory.createFromProduct(product);
consumer->consume();
Where the only thing that was ever specified, was ProducerA. Which, in my case, is the only thing that should be specified by the user. Also, I've isolated change areas to just two classes, the ConsumerFactory, and the IProductVisitor (which are very small changes to begin with).
If anyone could offer improvements or suggestions I'm all ears!
This is not the full solution (and maybe just a curiosity) but you can always do the tracking of types at compile time and use a bridging templated call to dispatch a product to the correct consumer.
#include <iostream>
template <class T>
class IProduct {
public:
virtual ~IProduct() {}
int intData;
typedef T consumer;
};
class ConsumerA;
class ProductA : public IProduct<ConsumerA> {
public:
float floatData;
};
class ConsumerB;
class ProductB : public IProduct<ConsumerB> {
public:
bool boolData;
};
template <class P, class C>
void apply(P* product, C* consumer) {
dynamic_cast<typename P::consumer*>(consumer)->consume(product);
}
template <class T>
class IConsumer {
public:
virtual void consume(IProduct<T>* prod) = 0;
};
class ConsumerA : public IConsumer<ConsumerA> {
public:
void consume(IProduct<ConsumerA>* prod) {
//I want to access the float!
std::cout << "ConsumerA" << std::endl;
std::cout << dynamic_cast<ProductA*>(prod)->floatData << std::endl;
}
};
class ConsumerB : public IConsumer<ConsumerB> {
public:
void consume(IProduct<ConsumerB>* prod) {
//I want to access the bool!
std::cout << "ConsumerB" << std::endl;
std::cout << dynamic_cast<ProductB*>(prod)->boolData << std::endl;
}
};
int main(int argc, char* argv[]) {
auto p_a = new ProductA;
auto c_a = new ConsumerA;
apply(p_a, c_a);
auto p_b = new ProductB;
auto c_b = new ConsumerB;
apply(p_b, c_b);
return 0;
}
I found this question while trying to solve a analogous issue. I ended up using std::any (which c++17 added to the language) to solve my problem. A single interface can return a std::any which you can cast back into the underlying type (via std::any_cast). In broad terms, std::any is like “hiding” types behind a void* pointer, but done in a type safe way, with full language and compiler support.
See:
std::any: How, when, and why
When should I use std::any
Related topic std::variant.
class Message {};
class BuildSandCastle : public Message {};
class DigHole : public Message {};
Given an arbitrary Message* object, how can I call a function of the same name doMessage() without resorting to switch logic or making a MessageHandler class that has one 'do' function for every message name?
EDIT: for example:
class Sandbox
{
public:
void play(Message* m)
{
// call doBuildSandCastle
// or doDigHole based on m's type
}
void doBuildSandCastle();
void doDigHole();
};
Sorry I wasn't clear before.
EDIT:
can someone just delete this train wreck of a question? I really don't want all these highschool lessons in polymorphism.
EDIT: Now that the question has been clarified, here is the new answer:
You can either get your message object to call the right function:
void play(Message* m) { m->play(this); }
or you could have a map of function pointers in Sandbox and execute the appropriate function based on the message name (or typeid), e.g.
handler_map[m.name()]();
I would use Boost::function to store function pointers in a map.
OLD ANSWER: I think what you need is virtual functions:
class Message
{
virtual void doMessage { std::cout << "message" << std::endl; }
};
class BuildSandCastle : public Message
{
virtual void doMessage { std::cout << "build sand castle" << std::endl; }
};
class BuildSandCastle : public Message
{
virtual void doMessage { std::cout << "dig hole" << std::endl; }
};
When you call doMessage like this:
Message* msg = new BuildSandCastle();
msg->doMessage();
it will output "build sand castle".
It sounds like you are just trying to add a polymorphic function to some classes.
Assuming any parameters and return values are the same on the sub classes, you can add a pure virtual function to the base class.
eg : (note: I didn't compile this, so apologies if there are typos)
class Message
{
public:
virtual void doMessage() = 0;
};
class BuildSandCaste : public Message
{
public:
void doMessage() { /* build a sand castle */ }
};
class DigHole : public Message
{
public:
void doMessage() { /* dig hole */ }
};
Use virtual functions.
class Message {
virtual void doSomething(...) = 0;
};
class ReportMessage : public Message {
virtual void doSomething(...) {
// (...) - specific for repors
}
};
class BankReportMessage : public ReportMessage {
virtual void doSomething(...) {
// (...) -||- for banks
}
};
Now, somewhere in your code:
Message* my_message = new BankReportMessage(...);
my_message->doSomething(...); // Would call appropriate function
Sounds like homework, so you should probably look at virtual functions (wikipedia). Message should probably have pure virtual doMessage, which gets overridden in the subclasses.
I was looking for something like this
class MessageHandlerBase
{};
template<typename MessageType>
class MessageHandler:
public virtual MessageHandlerBase
{
virtual void process(MessageType*)=0;
};
class Message
{
protected:
template<typename MessageType>
void dynamicDispatch(MessageHandlerBase* handler,MessageType* self)
{
dynamic_cast<MessageHandler<MessageType>&>(*handler).process(self);
}
};
class Message1:
public MessageBase
{
void dispatch(MessageHandlerBase* handler)
{
dynamicDispatch(handler,this);
}
};
Except without having to use dynamic_cast, or passing the message itself (a la the code in the original question.)