C++98 中获取并继续调用当前类不知道的类方法的最简单方法是什么?
What is the simplest way in C++98 to get and continue to call a class method, the type of which the current class does not know?
示例: 假设我们正在开发一个简单的图形界面:
我们有窗口和控件。我们想要什么:
- 有一个实现 GUI 功能的基窗口类 对用户隐藏。
- 从基窗口中,用户继承特定窗口。
- 有一个按钮类,用户可以将其实例添加到他的窗口中。
- 用户可以将窗口的方法转移到按钮,单击此按钮时将执行。
我对如何到达最后一点感兴趣。
伪代码的种类:
class BaseWindow;
class Button
{
public:
Button(BaseWindow* parent)
{
parent->AddButton(this);
}
void SetBehavior(/*Owners pointer and owner's methos*/)
{
/* Save Owner pointer and owner's method*/
}
void Clicked(/*coords*/)
{
if(/*coords == my coords*/)
{
/*Call Owner's method*/
}
}
};
class BaseWindow
{
vector<Button*> Buttons;
WindowClicked(/*coords*/)
{
for (std::vector<Button*>::iterator it = Buttons.begin(); it != Buttons.end(); ++it)
{
it->Clicked(/*coords*/);
}
}
public:
void AddButton(Button* butt)
{
Buttons<<butt;
}
};
class UserWindow:public BaseWindow
{
Button MyButton;
public:
void FunctionForButton(Button* butt){ cout<<"Say Hello, my sweet button";}
UserWindow():MyButton(this)
{
MyButton.SetBehavior(/*Put here my Function for Button and my pointer*/);
}
};
您可以考虑使用一些"纯"抽象类(在概念上最好将其视为接口,所以我会这样称呼它们!)来创建用于处理这些事件的临时协议。
例子:
class IEventHandler
{
public:
virtual ~IEventHandler() { }
virtual void HandleEvent(IEventData* const pEventData) = 0;
};
IEventHandler
提供了一个简单的抽象基类接口来处理事件,声明一个名为HandleEvent
的方法,接受指向IEventData
的指针的参数。
class IEventData
{
public:
virtual ~IEventData() = 0;
};
inline IEventData::~IEventData()
{
}
IEventData
提供了一个简单的抽象基类接口,用于向IEventHandler::HandleEvent
提供数据。
然后(使用您原来的伪代码作为起点,用更多的伪代码点缀:-)):
class BaseWindow;
class Button
{
public:
Button(BaseWindow* parent)
: pEventHandler_(NULL)
{
parent->AddButton(this);
}
void SetBehavior(IEventHandler* pEventHandler)
{
/* Save Owner pointer and owner's method*/
pEventHandler_ = pEventHandler;
}
void Clicked(/*coords*/)
{
if(/*coords == my coords*/)
{
IEventData* pData = new CoordinateEventData(/*coords*/);
/*Call Owner's method*/
pEventHandler_->HandleEvent(pData);
delete pData; /* if ownership not transferred to handler */
}
}
protected:
IEventHandler* pEventHandler_;
};
class BaseWindow
{
vector<Button*> Buttons;
WindowClicked(/*coords*/)
{
for(auto i:Buttons)
{
i->Clicked(/*coords*/);
}
}
public:
void AddButton(Button* butt)
{
Buttons<<butt;
}
};
class UserWindow:public BaseWindow
{
Button MyButton;
public:
void FunctionForButton(Button* butt){ cout<<"Say Hello, my sweet button";}
UserWindow():MyButton(this)
{
IEventHandler* pHandler = new CoordinateEventHandler(/*things and stuff*/);
MyButton.SetBehavior(pHandler);
}
};
您可以将适用于Button::Clicked
方法中的坐标的数据打包到CoordinateEventData
中。
您将转换/调整UserWindow::FunctionForButton
方法的实现以CoordinateEventHandler::HandleEvent
方法。
或者,你可以UserWindow
"实现"(派生自)IEventHandler
并使用来自(或通过调用)UserWindow::FunctionForButton
的代码实现IEventHandler::HandleEvent
,并使用MyButton.SetBehavior(this)
将其连接起来。
像往常一样,您需要注意指针所有权以避免泄漏。
希望能给你一些想法...
使用std::function<ReturnCode(Args...)>
。
假设您有一个 UI 上下文结构:
struct UI_context {
mouse_position mouse;
keyboard_state keyboard;
};
假设按钮支持几种操作:
struct button_trigger {
bool click;
bool enter;
bool touch;
bool pen;
};
您可以要求按钮执行以下几项操作:
struct click_result {
bool toggle;
bool flash;
bool wiggle;
};
然后你会存储一个std::function< click_result( button_trigger, UI_context ) >
.
当然,一个std::function<void()>
可能就是你想要的。 或者std::function<void(mouse_location)>
.
任何具有与您提供的签名兼容std::function
operator()
的内容都可以使用。 函数指针或 lambda 是最常见的两种。
您可能希望添加一种注册和删除回调的方法,和/或拥有令牌系统。
- 重载类方法的不明确调用
- 从基类实例调用派生类方法而不进行强制转换
- C++ - 如何在不静态的情况下将回调绑定到类方法?
- 我们可以在不知道其真实类型的情况下将基类指针转换为派生类指针吗?
- C++ 我不知道此代码中的输出过程(父类子级)
- 表达式必须具有类类型。不知道怎么解决
- msgpack:在不知道类型的情况下解包自定义类
- C++98 中获取并继续调用当前类不知道的类方法的最简单方法是什么?
- 当类方法不进行时,为什么从标头文件中的独立方法需要为命名空间资格
- 我不知道如何将变量从一个类中的方法传递和检索到另一个类的另一个方法
- 模板类方法不会导致错误——这是标准的一部分
- 类方法不起作用
- 如果您不知道所传递方法的确切类,如何将方法传递给类
- 视觉错误类 c++ 类。 不知道它是什么
- 使用虚拟重写基类方法不起作用
- 为什么类方法不能调用同名的全局函数?
- 不知道如何在main中调用类的方法
- 多重虚拟继承:为什么类方法不模棱两可?
- 当您不知道传递给重写函数的参数时,在基类中创建重写方法?
- C++ - 类方法不会从 dll 导出 (VS - win)