I also have another question about inheritance.
This isn't a rule of the site, but I'd generally recommend making new topics for new questions. It makes it easier for other new users who are Googling the same problem, and it increases the number of eyeballs you'll get from people who could help with your new question (who may not bother looking at the topic based on the title or old question).
I want to make a system so that the user can make a vector with "windows". the window element have the description of the window but also I need to store the information about behavior on different action and I dont know how to proceed with that.
You're roughly asking for a signals or delegate system.
The rough C and old C++ way to do this is to use raw function pointers. More modern C++ should use std::function. The _bad_ object-oriented way is to use virtual methods.
A more flexible way is to actually use a signals+slots library. You can get one from
Boost if you don't mind depending on another giant header-only (read: slower to compile) library.
There's also a bunch of other
signals+slots libraries for C++, though I can't attest to the quality of most of them.
Once you're more comfortable with C++, writing your own is also rather easy. The Signal.h in my toy code is only around 50 lines of code.
If you're brave, here's some adapted (and untested) code modified to use the standard C++ types (and also with some error-checking removed, as it depended on some custom assertion macros):
#include <functional>
#include <vector>
#include <memory>
#include <algorithm>
template <typename...> class Signal;
/// Derive from this to be able to attach methods of a class to Signal.
class Slotted
{
std::shared_ptr<int> m_Lifetime;
public:
std::weak_ptr<int> GetSlottedLifetime()
{
if (!m_Lifetime)
m_Lifetime = std::make_shared<int>(/*unused*/0);
return m_Lifetime;
}
}
/// Connect callbacks to a signal to get notified of a specific event.
template <typename... ParamsT>
class Signal<void(ParamsT...)>
{
using Signature = void(ParamsT...);
std::vector<std::pair<std::weak_ptr<int>, std::function<Signature>>> m_Callbacks;
public:
template <typename... InputT>
void operator()(InputT&&... argv)
{
for (auto& callback : m_Callbacks)
if (auto _= callback.first.lock()) // ensure the object hasn't/won't-be expired
callback.second(std::forward<InputT>(argv)...);
m_Callbacks.erase(std::remove_if(m_Callbacks.begin(), m_Callbacks.end(), [](auto& callback){ return callback.first.expired(); }), m_Callbacks.end());
}
template <typename ObjectT, typename... InputT>
void connect(ObjectT& receiver, void (ObjectT::*method)(InputT...))
{
return connect(receiver, [=](auto&&... argv){ return (receiver.*method)(std::forward<decltype(argv)>(argv)...); });
}
template <typename FunctorT>
void connect(Slotted& slotted, FunctorT&& functor)
{
m_Callbacks.push_back({slotted.GetSlottedLifetime(), std::forward<FunctorT>(functor)});
}
};
That doesn't use slots in the usual sense, but rather just allows you to attach signals to any object that derives from Slotted. You can also, via the second connect() overload, use some _other_ object to track lifetime for a given functor, which has all kinds of uses (for instance, in a component-based engine, you can use the base GameObject for lifetime tracking of signals attached to component methods, rather than needing each component to be a shared_ptr-owned object).
Note that yes, the shared_ptr/weak_ptr usage is a little weird, but there's no good workaround for that which doesn't involve new extra code for lifetime tracking (which is what I do in my code) or forcing all your objects to themselves use shared ownership (which is terrible, don't do that).
The code above doesn't let you remove individual connected signals. I had that code, but it ended up being unused, so I stripped it out as part of an optimization pass. There's some further optimization that can be done (removing the second pass for the std::remove_if for instance).
Note also that the code is not thread-safe and also not re-entrant, so be wary of those. You can make it re-entrant easily enough, and thread safety could be achieved with some mutexes.