I would like to add support for protobuf events to my existing event queue.
I wrote a proof-of-concept (see below), which seemed to work fine at first. Unfortunately, compilation aborts when accessing inherited data members. Accessing inherited function members works just fine. Following classes are declared:
Abstract class SubscriptionHolderBase: This is the interface base class
Abstract class SubscriptionHolderCommon: Is supposed to hold the common members of the following two classes.
Depending on the type of the event to subscribe, the compiler shall automatically choose one of the following classes to instantiate:
Template class SubscriptionHolder, specialized for normal events.
Templace class SubscriptionHolder, spezialized for all other (i.e. protobuf) events.
For some reason, SubscriptionHolder seems to inherit the function member of SubscriptionHolderCommon just fine, but when trying to access the data member _member_var (inherited from the same class), following error message is produced:
error: ‘_member_var’ was not declared in this scope
Can someone explain the reason?
My proof-of-concept code:
When commenting all 3 occurences of _member_var, it is doing just fine.
You can compile and let it run online here.
#include <type_traits>
#include <iostream>
class ProtobufEvent {
};
class Proto2 : public ProtobufEvent {
};
class Event {
public:
virtual ~Event(){};
};
class SubscriptionHolderBase {
public:
virtual bool dispatch(Event* event) = 0;
virtual void handle() = 0;
};
template<typename EventType>
class SubscriptionHolderCommon : public SubscriptionHolderBase {
public:
void handle() {
std::cout << "Member function of unspecialized common base class called." << std::endl;
}
protected:
bool _member_var;
};
template<typename EventType, typename Enable = void>
class SubscriptionHolder;
template<typename EventType>
class SubscriptionHolder<EventType, typename std::enable_if<std::is_convertible<EventType*, ProtobufEvent*>::value>::type> : public SubscriptionHolderCommon<EventType> {
public:
virtual bool dispatch(Event* event);
};
template<typename EventType>
class SubscriptionHolder<EventType, typename std::enable_if<!std::is_convertible<EventType*, ProtobufEvent*>::value>::type> : public SubscriptionHolderCommon<EventType> {
public:
virtual bool dispatch(Event* event);
};
template<typename EventType>
bool SubscriptionHolder<EventType, typename std::enable_if<std::is_convertible<EventType*, ProtobufEvent*>::value>::type>::dispatch(Event* event) {
std::cout << "Member function of specialized class for protobuf event called." << std::endl;
_member_var = true;
return false;
}
template<typename EventType>
bool SubscriptionHolder<EventType, typename std::enable_if<!std::is_convertible<EventType*, ProtobufEvent*>::value>::type>::dispatch(Event* event) {
std::cout << "Member function of specialized class for standard event called." << std::endl;
_member_var = true;
return false;
}
int main() {
Event* e = nullptr;
SubscriptionHolderBase* ptr;
SubscriptionHolder<Event> s_e;
ptr = &s_e;
ptr->handle();
ptr->dispatch(e);
std::cout << std::endl;
SubscriptionHolder<ProtobufEvent> s_p;
ptr = &s_p;
ptr->handle();
ptr->dispatch(e);
std::cout << std::endl;
SubscriptionHolder<Proto2> s_p2;
ptr = &s_p2;
ptr->handle();
ptr->dispatch(e);
std::cout << std::endl;
}
Related
I'll start by explaining my situation.
I have a base class that automatically implements a type of reference counting. It allows me to wrap C-style init() and free() library calls into a reference-counted API.
template<typename T>
class Service {
public:
Service() {
if(s_count++ == 0) {
T::initialize();
}
}
~Service() {
if(--s_count == 0) {
T::terminate();
}
}
private:
static int s_count;
};
template<typename T>
int Service<T>::s_count = 0;
Classes that wish to implement these initializers and terminators will derive from Service like so:
class Test : public Service<Test> {
friend class Service<Test>;
private:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
However, the declaration is messy since I have to both inherit from and friend my Service class. Is there any way to allow a base class access to protected or private members of a derived class automatically? If not, I may as well ask if there's any better way to write what I've done here.
"Is there any way to allow a base class access to protected or private members of a derived class automatically?"
Base class cannot access private/protected members of derived class formally. In general base classes are designed such a way that they don't need to know anything of derived class. So, if there is a need to access members in derived class from your base class then you should re-consider your design.
EDIT ( As per proposed article by #RSahu ):-
Although there are some scenario where it might be useful to access member functions of derived class from base class. Like when you are sharing objects between two processes.
#include <iostream>
using namespace std;
template<typename T>
class Service {
struct TT: T {
using T::initialize;
using T::terminate;
};
public:
Service() {
if(s_count++ == 0) {
TT::initialize();
}
}
~Service() {
if(--s_count == 0) {
TT::terminate();
}
}
private:
static int s_count;
};
class Test : public Service<Test> {
//friend class Service<Test>;
protected:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
template<typename T>
int Service<T>::s_count = 0;
int main() {
Test t;
}
n.m.'s suggestion of making these methods virtual made me think: it would not work by itself, but it would work if you decouple the service from its management: the initialization doesn't just applies to that particular service instance, it applies to all instances, and perhaps because of that it just shouldn't be part of the service class in the first place.
If you decouple them, you can make a service manager base class, with virtual methods that a derived service manager must implement, like so:
#include <iostream>
class ServiceManager {
template <typename T>
friend class Service;
virtual void initialize() = 0;
virtual void terminate() = 0;
};
template <typename T>
class Service {
public:
Service() {
if (s_count++ == 0) {
s_manager.initialize();
}
}
~Service() {
if (--s_count == 0) {
s_manager.terminate();
}
}
private:
static int s_count;
static ServiceManager &&s_manager;
};
template <typename T>
int Service<T>::s_count = 0;
template <typename T>
ServiceManager &&Service<T>::s_manager = T();
class TestManager : public ServiceManager {
void initialize() {
std::cout << "Initialized" << std::endl;
}
void terminate() {
std::cout << "Terminated" << std::endl;
}
};
class Test : public Service<TestManager> {
};
If your compiler doesn't support this use of && (it's valid C++11, but not valid C++03), you should still be able to easily adapt the code by either making s_manager ServiceManager & and not using a temporary T to initialise it, or just making s_manager have type T. The former is more verbose, the latter allows T implementations that do not derive from ServiceManager.
I am trying to hide serious design flaws in my application behind event bus :)
I created template class with static event handlers holder like this:
template<typename ET>
class EventHandler;
template<typename ET>
class EventBus {
public:
static std::vector<EventHandler<ET>*> handlers;
};
template<typename ET>
std::vector<EventHandler<ET>*> EventBus<ET>::handlers = std::vector<EventHandler<ET>*>();
Next part of my 'event-bus' is template class for event handler:
template<typename ET>
class EventHandler {
public:
EventHandler() {
EventBus<ET>::handlers.emplace_back(this);
}
~EventHandler() {
auto &handlers=EventBus<ET>::handlers;
handlers.erase(std::remove(handlers.begin(), handlers.end(), this), handlers.end());
}
virtual void handle_event(ET &event) = 0;
};
Here is a complete code with example usage:
#include <iostream>
#include <vector>
#include <map>
template<typename ET>
class EventHandler;
template<typename ET>
class EventBus {
public:
static std::vector<EventHandler<ET>*> handlers;
};
template<typename ET>
std::vector<EventHandler<ET>*> EventBus<ET>::handlers = std::vector<EventHandler<ET>*>();
template<typename ET>
class EventHandler {
public:
EventHandler() {
EventBus<ET>::handlers.emplace_back(this);
}
~EventHandler() {
auto &handlers=EventBus<ET>::handlers;
handlers.erase(std::remove(handlers.begin(), handlers.end(), this), handlers.end());
}
virtual void handle_event(ET &event) = 0;
};
template<typename ET>
void publish(ET &event) {
for(auto handler : EventBus<ET>::handlers) {
handler->handle_event(event);
}
}
class MyClass: public EventHandler<int>, public EventHandler<std::string> {
public:
void handle_event(int &event) override {
std::cout << "handling int event" << std::endl;
}
void handle_event(std::string &event) override {
std::cout << "handling std::string event" << std::endl;
}
};
int main() {
int eventData = 1;
MyClass eventHandler2;
std::string stringEventData = "hello, world";
{
MyClass eventHandler;
publish(eventData);
publish(stringEventData);
}
publish(eventData);
publish(stringEventData);
std::cout << "Hello, World!" << std::endl;
return 0;
}
So the question is - is there some chance that I will have issues with resolving correct handle_event method based on event type with mulptiple inheritance?
There won't be any issues resolving the handle_event overload with the given publish() function, because only one handle_event member function is actually visible in this function: the type being invoked on is EventHandler<ET>, which only knows about handle_event(ET&) (whatever ET happens to be).
For example, if ET is int, this function doesn't even see the handle_event(std::string&) overload because that overload isn't part of the EventHandler<int> interface.
I'll start by explaining my situation.
I have a base class that automatically implements a type of reference counting. It allows me to wrap C-style init() and free() library calls into a reference-counted API.
template<typename T>
class Service {
public:
Service() {
if(s_count++ == 0) {
T::initialize();
}
}
~Service() {
if(--s_count == 0) {
T::terminate();
}
}
private:
static int s_count;
};
template<typename T>
int Service<T>::s_count = 0;
Classes that wish to implement these initializers and terminators will derive from Service like so:
class Test : public Service<Test> {
friend class Service<Test>;
private:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
However, the declaration is messy since I have to both inherit from and friend my Service class. Is there any way to allow a base class access to protected or private members of a derived class automatically? If not, I may as well ask if there's any better way to write what I've done here.
"Is there any way to allow a base class access to protected or private members of a derived class automatically?"
Base class cannot access private/protected members of derived class formally. In general base classes are designed such a way that they don't need to know anything of derived class. So, if there is a need to access members in derived class from your base class then you should re-consider your design.
EDIT ( As per proposed article by #RSahu ):-
Although there are some scenario where it might be useful to access member functions of derived class from base class. Like when you are sharing objects between two processes.
#include <iostream>
using namespace std;
template<typename T>
class Service {
struct TT: T {
using T::initialize;
using T::terminate;
};
public:
Service() {
if(s_count++ == 0) {
TT::initialize();
}
}
~Service() {
if(--s_count == 0) {
TT::terminate();
}
}
private:
static int s_count;
};
class Test : public Service<Test> {
//friend class Service<Test>;
protected:
static void initialize() {
std::cout << "Initialized" << std::endl;
}
static void terminate() {
std::cout << "Terminated" << std::endl;
}
};
template<typename T>
int Service<T>::s_count = 0;
int main() {
Test t;
}
n.m.'s suggestion of making these methods virtual made me think: it would not work by itself, but it would work if you decouple the service from its management: the initialization doesn't just applies to that particular service instance, it applies to all instances, and perhaps because of that it just shouldn't be part of the service class in the first place.
If you decouple them, you can make a service manager base class, with virtual methods that a derived service manager must implement, like so:
#include <iostream>
class ServiceManager {
template <typename T>
friend class Service;
virtual void initialize() = 0;
virtual void terminate() = 0;
};
template <typename T>
class Service {
public:
Service() {
if (s_count++ == 0) {
s_manager.initialize();
}
}
~Service() {
if (--s_count == 0) {
s_manager.terminate();
}
}
private:
static int s_count;
static ServiceManager &&s_manager;
};
template <typename T>
int Service<T>::s_count = 0;
template <typename T>
ServiceManager &&Service<T>::s_manager = T();
class TestManager : public ServiceManager {
void initialize() {
std::cout << "Initialized" << std::endl;
}
void terminate() {
std::cout << "Terminated" << std::endl;
}
};
class Test : public Service<TestManager> {
};
If your compiler doesn't support this use of && (it's valid C++11, but not valid C++03), you should still be able to easily adapt the code by either making s_manager ServiceManager & and not using a temporary T to initialise it, or just making s_manager have type T. The former is more verbose, the latter allows T implementations that do not derive from ServiceManager.
I have the case where I am deriving a class from two different base classes both having a static function with the same name.
To resolve this ambiguity, I tried to use the scope operator - just as I would do for a member function. However This does not compile. Why? Wrong syntax?
I want to call the static function via the derived typename and not directly via base class name. Actually I would like prefer to prevent this case, but I have no idea how to do so.
The error (commented out) in the code below also occurs, when I leave the templates away:
#include <iostream>
template<class TDerived>
class StaticBaseA
{
public:
static void announce()
{
std::cout << "do something" << std::endl;
}
};
template<class TDerived>
class StaticBaseB
{
public:
static void announce()
{
std::cout << "do something else" << std::endl;
}
};
class Derived :
public StaticBaseA<Derived>
, public StaticBaseB<Derived>
{
using StaticBaseA<Derived>::announce;
};
class NonDerived {};
int main(int argc, char* argv[])
{
Derived::announce();
// What I want:
//Derived::StaticBaseB<Derived>::announce(); Error: "Undefined symbol 'StaticBaseB'
// What works, but what I don't want ...
StaticBaseB<Derived>::announce();
// ... because I would like to prevent this (however this is done):
StaticBaseB<NonDerived>::announce();
return 0;
}
Making "announce" protected in StaticBaseA and StaticBaseB might be part-way to doing what you want.
You then could not call StaticBaseB<NonDerived>::announce from main as it would be inaccessible. You could call it from a class derived from StaticBaseB.
In other words:
template<class TDerived>
class StaticBaseA
{
protected:
static void announce()
{
std::cout << "do something" << std::endl;
}
};
template<class TDerived>
class StaticBaseB
{
protected:
static void announce()
{
std::cout << "do something else" << std::endl;
}
};
In Derived you have to promote "announce" to public.
class Derived : public StaticA<Derived>, public StaticB<Derived >
{
public:
using StaticA<Derived>::announce;
};
int main()
{
Derived::announce(); // legal and calls StaticBaseA::announce
NotDerived::announce(); // no such function
StaticBaseA< Derived >::announce(); // not accessible
StaticBaseB< Derived >::announce(); // also not accessible
StaticBaseA< NotDerived >::announce(); // not accessible
StaticBaseB< NotDerived >::announce(); // also not accessible
}
I'm currently trying to build a class hierarchy automatically by using C++ templates. The final result is a message handler class that provides handler functions for all possible messages, given in a typelist.
However when inheriting from that class hierarchy and trying to implement the handler function to actually do the application code for some types only, C++ isn't calling the function from the base class.
The following is a minimal and complete example what I'm trying to achieve. It doesn't compile because C++ complains about not finding an overload for handle( const B& ).
#include <iostream>
#include <typeinfo>
// Typelist.
struct None {};
template <class H, class T = None>
struct Typelist {
typedef H Head;
typedef T Tail;
};
template <class TL>
struct Handler : public Handler<typename TL::Tail> {
using Handler<typename TL::Tail>::handle;
virtual void handle( const typename TL::Head& obj ) {
std::cout << "Not handled! " << typeid( typename TL::Head ).name() << std::endl;
}
};
template <>
struct Handler<None> {
virtual void handle() {}
};
struct A {};
struct B {};
typedef Typelist<A, Typelist<B> > MsgList;
struct MyHandler : Handler<MsgList> {
void handle( const A& a ) {
std::cout << "A!" << std::endl;
}
};
int main() {
MyHandler handler;
A a;
B b;
handler.handle( a );
handler.handle( b );
}
You need to use handle from you Handle<MsgList> in your MyHandler class
using Handler<MsgList>::handle;
Right now it is hidden and do not overload the name handle in MyHandler class. And taking into account the code of the Handler, you know this :-)