我似乎找到了一个案例,我应该遭受“可怕的”钻石继承问题。但是,代码似乎工作得很好。我似乎无法确定的是,如果可能成为一个问题。
这是设置。我正在使用MFC并扩展了CEdit以添加鼠标单击窗口消息的自定义处理。然后我继承了这个类和一个由第三方开发人员编写的类(在这个例子中称他为Bob)。这样做,我现在可以返回我的特殊控件或Bob的控件的增强版本。问题是,Bob的库无法修改,我们的代码最终都继承自CEdit(以及CWnd)。
示例代码:
class A : public CEdit {...} // From Bob's library
class B : public A {...} // From Bob's library
class BobsEdit : public B {...} // From Bob's library
// My version which handles WM_LBUTTONDOWN, WM_CREATE
// and does a couple other cool things.
class MyEdit : public CEdit
{
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if ( !CEdit::Create(...) ) return -1;
...set some style stuff...
}
afx_msg void OnLButtonDown(UINT nFlags,CPoint point) {} // Override CWnd handler
}
class MyBobsEdit : public BobsEdit, public MyEdit {} // My version of Bob's control
// CBobsUser returns just a standard CEdit and BobsEdit control
// This is also from Bob's library.
class CBobsUser
{
CWnd* GetMeAnEditBox()
{
CEdit* pEdit;
if ( ...some condition... )
pEdit = new CEdit();
else
pEdit = new BobsEdit();
...
return pEdit;
}
}
// CMyUser overrides Bob's GetMeAnEditBox and returns
// one of my custom controls (with the new cool handler).
class CMyUser : public CBobsUser
{
...
CWnd* GetMeAnEditBox()
{
MyEdit* pEdit;
if ( ...some condition... )
pEdit = new MyEdit();
else
pEdit = new MyBobsEdit();
...
return pEdit;
}
}
所以...问题是:
谢谢!
答案 0 :(得分:3)
广告1:因为没有人知道对象是CBobsEdit
。您将对象创建为MyBobsEdit
,但立即将其强制转换为MyEdit
,因此所有方法调用都在MyEdit
上,并且不会出现明显的调用错误,并且转换本身也不含糊。没有使用CBobsEdit
的任何功能(子类中没有任何方法)。它是构造的,但它永远不会被添加到父级,所以它从未显示过,也从未使用过。
广告2:嗯,您根本没有使用BobsEdit
。我想,这不是你想要的。
广告3 :您可以使MyEdit
模板继承自其模板参数,并在一种情况下直接从CEdit
继承,并从CBobsEdit
继承在另一种情况下。这种技术通常被称为“mixin”。像:
template <typename BaseEditT>
class MyEdit : public BaseEditT { ... }
不幸的是MyEdit<CEdit>
和MyEdit<CBobsEdit>
是不相关的类。如果可以将指针存储为CEdit
(它始终是基类),则必须定义接口,在MyEdit中实现此接口并存储指向该接口的指针。界面需要包含一个强制转换操作符CEdit&
(和CEdit const&
),并且您应该可以在其上调用任何CEdit
方法。像这样:
class IMyEdit {
virtual operator CEdit &() = 0;
virtual operator CEdit const &() const = 0;
};
template <typename BaseEditT>
class MyEdit : public BaseEditT {
operator CEdit &() { return *this; }
operator CEdit const &() const { return *this; }
};
请注意,只有构造对象的代码才需要查看MyEdit
模板的定义,因此您可以将其放在单独的文件中,并仅在将CMyUser
构造函数定义到的位置包含它避免在编译时受到惩罚。