依赖循环

时间:2013-07-17 07:47:44

标签: c++ inheritance dependencies containers circular-dependency

我设计了一个继承自CDialog的对象(称为NBDialog)和一些控件的派生对象,例如CEditCDateTimeCtrlCComboBox
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不知道控件类的上下文:< / p>

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;
}

有没有办法编写所需的方法?

2 个答案:

答案 0 :(得分:1)

最简单的方法是为此定义一个接口并添加该接口而不是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);
    }
}

或者使用自定义窗口消息并迭代所有控件,向下转换为CWnd并在其HWND上使用SendMessage。每个控件都需要处理您的自定义windoes mesaage。您可以将指针传递给消息的LPARAM中的字符串列表。这个apprach是灵活的,但有点脆弱/不安全,如果你最终意外地使用相同的消息ID,可能会崩溃。

答案 1 :(得分:0)

您的实施文件(NBDialog.cpp)可以#include免费获得必要的标题以使其发挥作用(可能是NBCommonComboBox.h之类的内容等)因为.cpp文件不是“#include”任何你不会导致任何循环的问题包括问题。