指向成员函数、模板和成员函数的指针继承混合
我正在尝试创建一个通用的“回调”对象,该对象将保存任意数据并调用相关类的成员函数。由于内部政策,我无法使用 Boost。
回调对象如下所示:
template<typename Object, typename Data>
class Callback
{
public:
typedef void (Object::*PHandler)(Callback*);
Callback(Object* obj, PHandler handler) : pObj(obj), pHandler(handler) {}
Callback& set(PHandler handler) { pHandler = handler; return *this; }
void run() { (pObj->*pHandler)(this); }
public:
Data data;
protected:
Object* pObj;
PHandler pHandler;
};
以及它所作用的类:
struct Object1
{
struct Data { int i; };
typedef Callback<Object1, Data> Callback1;
void callback(Callback1* pDisp) { printf("%cb\n", pDisp->data.i); }
void test()
{
Callback1 cb(this, &Object1::callback);
cb.data.i = 1;
cb.run();
}
};
以下测试按预期工作:
Object1 obj1;
obj1.test();
到目前为止一切顺利。
然而,当一位同事尝试从 Callback 类而不是使用 typedef 派生时,他们由于不兼容的指针而出现编译错误:
struct Object2
{
struct Data { int i; Data(int j) { i = j; } };
class Callback2 : public Callback<Object2, Data>
{
Callback2(Object2* obj, PHandler handler, int i) : Callback(obj, handler) { data.i = i; }
};
void callback(Callback2* pDisp) { printf("%cb\n", pDisp->data.i); }
void test()
{
Callback2 cb(this, &Object2::callback, 2);
cb.run();
}
};
我尝试使用“奇怪的重复模板模式” ” 在 Callback 类中并设法使派生类正常工作,但它破坏了使用 typedef
方法的代码。
我的问题是:
如何修改 Callback
类以适应这两种情况,并且不需要类用户进行额外的工作?< /em>
I am trying to create a generic "callback" object that will hold arbitrary data and invoke member functions of related classes. Due to internal policy, I cannot use Boost.
The callback object looks like this:
template<typename Object, typename Data>
class Callback
{
public:
typedef void (Object::*PHandler)(Callback*);
Callback(Object* obj, PHandler handler) : pObj(obj), pHandler(handler) {}
Callback& set(PHandler handler) { pHandler = handler; return *this; }
void run() { (pObj->*pHandler)(this); }
public:
Data data;
protected:
Object* pObj;
PHandler pHandler;
};
And the class it works on:
struct Object1
{
struct Data { int i; };
typedef Callback<Object1, Data> Callback1;
void callback(Callback1* pDisp) { printf("%cb\n", pDisp->data.i); }
void test()
{
Callback1 cb(this, &Object1::callback);
cb.data.i = 1;
cb.run();
}
};
The following test works as expected:
Object1 obj1;
obj1.test();
So far so good.
However, when a coworker tried to derive from the Callback
class instead of using a typedef
, they got compilation errors due to incompatible pointers:
struct Object2
{
struct Data { int i; Data(int j) { i = j; } };
class Callback2 : public Callback<Object2, Data>
{
Callback2(Object2* obj, PHandler handler, int i) : Callback(obj, handler) { data.i = i; }
};
void callback(Callback2* pDisp) { printf("%cb\n", pDisp->data.i); }
void test()
{
Callback2 cb(this, &Object2::callback, 2);
cb.run();
}
};
I tried using the "curiously recurring template pattern" in the Callback class and managed to get derived classes working, but it broke code that used the typedef
method.
My question is:
How can I modify the Callback
class to work with both cases, and without requiring extra work on the part of the user of the class?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不幸的是,你在一家提倡重新发明轮子并使用青铜时代 C++ 的公司工作。但是,考虑到您发布的情况和代码,有一个相当简单的解决方案,无需进行太多更改。我以前也曾做过类似的事情,不是因为公司政策,而是因为我们正在开发一个软件开发工具包,并且我们不想要求 SDK 的用户安装特定版本的 boost。
顺便说一句,我相信你真正追求的是信号和槽机制:如果你想让这个设计更符合既定的解决方案,我建议你研究它。
我采取了一些自由假设:第一个假设是数据不必存储在回调中,而是可以由发送者传递。这应该是一个比较灵活的设计。它仍然非常简单 - 您可以更进一步(例如:可变数量的参数和自定义返回类型、信号类、延迟通知等)。
用法示例:
如您所见,Callback 对象本身不需要将对象类型作为模板参数传入,从而允许它指向任何类型的方法,只要该方法符合签名:void some_class:: some_method(const Data&).将这些回调对象的列表存储在能够调用所有回调对象的类中,并且您自己拥有一个带有连接槽的信号。
It is unfortunate that you work for a company which advocates reinventing wheels and using bronze age C++. However, given the circumstances and the code you posted, there is a fairly simple solution without making too many changes. I've had to do similar things before not because of company policy but because we were developing a software development kit and we did not want to require that users of the SDK have a specific version of boost installed.
BTW, I believe what you are really after is a signals and slots mechanism: I suggest studying it if you want to make this design a bit more conforming to well-established solutions.
I took a few liberal assumptions: the primary one being that Data does not have to be stored in the callback and can instead be passed by the sender. This should be a more flexible design. It is still very simple - you can take this a lot further (ex: variable-number of arguments and custom return types, a signal class, deferred notifications, etc).
Example usage:
As you can see, the Callback object itself does not require the object type to be passed in as a template argument, thereby allowing it to point to methods of any type provided that the method conforms to the signature: void some_class::some_method(const Data&). Store a list of these Callback objects in a class capable of calling all of them and you have yourself a signal with connected slots.
您必须传递派生类的类类型。为了不破坏 typedef-way,您可以为该参数指定一个默认值。像下面这样的东西应该可以工作
或者你可以简单地有两个类来实现这一点。一份用于继承,一份用于不继承。第一个是继承
,第二个是非继承。您可以为此使用基类
You have to pass the class type of the derived. To not break the typedef-way, you can can give that parameter a default value. Something like the following should work
Alternatively you can simply have two classes for this. One for inheritance and one if you don't inherit. The first is for inheritance
And the second is for non-inheritance. You can make use of the base-class for this
由于内部政策,我无法使用 Boost。
退出;)
但是,当一位同事尝试从 Callback 类派生而不是使用 typedef 时
射杀他们。
我对你有感觉,真的。
Due to internal policy, I cannot use Boost.
Quit ;)
However, when a coworker tried to derive from the Callback class instead of using a typedef
Shoot them.
I feel for you, I really do.