我设计了一个对象,该对象继承自CDialog
(称为NBDialog
)和某些控件的派生对象,例如CEdit
,CDateTimeCtrl
,CComboBox
等。NBDialog
是一个项目,而控件在其他项目中。
自然,所有控件都放在对话框上并使用对话框的方法,所以我必须#include NBDialog.h
,并为链接器添加其.lib
文件。
我还想从对话框中处理所有这些控件,因此我在NBDialog.h
中写了以下几行:
class NBCommonEditBox;
class NBDateTimeCtrl;
class NBCommonComboBox;
CMapWordToOb* NBGetEditBoxMap();
NBCommonEditBox* NBGetEditBoxById(unsigned long ID);
CMapWordToOb* NBGetDateTimeMap();
NBDateTimeCtrl* NBGetDateTimeById(unsigned long ID);
CMapWordToOb* NBGetComboBoxMap();
NBCommonComboBox* NBGetComboBoxById(unsigned long ID);
这样,
NBDialog.h
不知道对象的上下文,但是知道它们的存在并将它们存储在地图中。现在,我想扩展
NBDialog
项目并添加一个方法,该方法将获取所有控件的打印信息,因此从NBDialog
继承的所有对象都将能够使用此方法。打印信息在控件实现中定义。编辑:如果我在
NBDialog.cpp
中编写此方法,则无法编译它,因为NBDialog
不知道控件类的上下文:CStringList* NBDialog::NBGetMainTexts()
{
CStringList* mainTexts = new CStringList();
POSITION pos;
WORD key;
NBCommonEditBox* currEdit = NULL;
for (pos = this->NBGetEditBoxMap()->GetStartPosition(); pos != NULL;)
{
this->NBGetEditBoxMap()->GetNextAssoc(pos, key, (CObject*&)currEdit);
currEdit->NBStringsToPrint(mainTexts);
}
return mainTexts;
}
有没有办法编写所需的方法?
最佳答案
最简单的方法是为此定义一个接口,然后添加该接口而不是CObject。该接口可以提供一种获取控件本身的方法。别担心多重继承-是的,它可能会带来轻微的性能损失,但这对您来说不是问题。在这种情况下,它将类似于Java中的接口继承,因为您将使用纯接口。
您也可以通过类似的方式来实现这一点,从而避免多重继承,但会增加您不需要的复杂性。
// Interface goes in the NBDialog project
class INBControl {
public:
virtual ~INBControl() = 0;
virtual CWnd* getWnd() = 0;
virtual void getStringsToPrint(CStringList& strings) = 0;
};
inline INBControl::~INBControl() {}
class NBCommonComboBox : public CComboBox, public INBControl
{
public:
// ... stuff ...
virtual CWnd* getWnd() {
return this;
}
virtual void getStringsToPrint(CStringList& strings) {
strings.AddTail("foo"); // for example
}
};
// NBDialog
#include <map>
class NBDialog : public CDialog
{
public:
// .. stuff ..
private:
typedef std::map<int, INBControl*> ControlMap;
ControlMap control_map_;
};
void NBDialog::addNBControl(INBControl* control, int id)
{
CWnd* wnd = control->getWnd();
// Do stuff with the control such as add it
control_map_[id] = control;
}
// let the caller be responsible for [de]allocation of the string list
void NBDialog::NBGetMainTexts(CStringList& texts)
{
ControlMap::iterator i = control_map_.begin();
ControlMap::iterator e = control_map_.end();
for(; i != e; ++i) {
i->second->getStringsToPrint(texts);
}
}
或者,使用自定义Windows消息并迭代所有控件,向下广播到CWnd,并在其HWND上使用SendMessage。每个控件都需要处理您的自定义窗口消息。您可以将指针传递到消息的LPARAM中的字符串列表。此方法很灵活,但有些脆弱/不安全,如果您偶然对其他东西使用相同的消息ID,则可能会崩溃。