只是为了好玩,我正在为 Windows 开发一个 XUL 实现。在 XUL 中,UI 元素可以像这样用 XML 编写:
<window width="800" height="600"></window>
我正在考虑一个获取和设置元素属性的系统。它工作得很好,但我不确定在这里使用钻石继承是否有潜在危险。我在下面发布了一个完整的代码示例:
#include <boost/lexical_cast.hpp>
#include <string>
#include <map>
class Attribute
{
public:
virtual void get(std::string & outValue) = 0;
virtual void set(const std::string & inValue) = 0;
static int String2Int(const std::string & inString)
{
return boost::lexical_cast<int>(inString);
}
static std::string Int2String(int inValue)
{
return boost::lexical_cast<std::string>(inValue);
}
};
class Width : public Attribute
{
public:
Width(){}
virtual void get(std::string & outValue)
{
outValue = Int2String(getWidth());
}
virtual void set(const std::string & inValue)
{
setWidth(String2Int(inValue));
}
virtual int getWidth() const = 0;
virtual void setWidth(int inWidth) = 0;
};
class Height : public Attribute
{
public:
Height(){}
virtual void get(std::string & outValue)
{
outValue = Int2String(getHeight());
}
virtual void set(const std::string & inValue)
{
setHeight(String2Int(inValue));
}
virtual int getHeight() const = 0;
virtual void setHeight(int inHeight) = 0;
};
class Element : public Width, // concerning the is-a vs has-a philosophy
public Height // => see my note below
{
public:
Element() :
mWidth(0),
mHeight(0)
{
// STATIC CAST NEEDED HERE OTHERWISE WE GET COMPILER ERROR:
// error C2594: '=' : ambiguous conversions from 'Element *const ' to 'Attribute *'
mAttrControllers["width"] = static_cast<Width*>(this);
mAttrControllers["height"] = static_cast<Height*>(this);
}
void setAttribute(const std::string & inAttrName, const std::string & inAttrValue)
{
Attributes::iterator it = mAttrControllers.find(inAttrName);
if (it != mAttrControllers.end())
{
Attribute * attribute = it->second;
attribute->set(inAttrValue);
}
}
std::string getAttribute(const std::string & inAttrName)
{
std::string result;
Attributes::iterator it = mAttrControllers.find(inAttrName);
if (it != mAttrControllers.end())
{
Attribute * attribute = it->second;
attribute->get(result);
}
return result;
}
virtual int getWidth() const
{
return mWidth;
}
virtual void setWidth(int inWidth)
{
mWidth = inWidth;
}
virtual int getHeight() const
{
return mHeight;
}
virtual void setHeight(int inHeight)
{
mHeight = inHeight;
}
private:
typedef std::map<std::string, Attribute *> Attributes;
Attributes mAttrControllers;
int mWidth;
int mHeight;
};
int main()
{
Element el;
el.setAttribute("width", "800");
el.setAttribute("height", "600");
int w = el.getWidth();
int h = el.getHeight();
return 0;
}
我认为没关系,因为基类 Attributes 没有数据成员,所以那里不会出现冲突。但我想我会与社区核实。非常感谢您的见解!
编辑 关于“is-a”与“has-a”,以及“偏好组合优于继承”的评论我有这样的说法:
- 这里继承有一个优势。如果 Element 继承了 Width ,则强制实现 getWidth 和 setWidth 方法。所以添加一个属性意味着元素界面的“自动”更新。
- 我最初将这些类命名为 AttributeController、WidthController 和 HeightController,但我发现它们太冗长了。你可以说我的 Element 是一个属性控制器。(好吧,这很蹩脚,但并非不真实!)
- 进一步证明:Width 和 Height 的定义不包含任何数据成员。Element 类实际上有它们。Width 和 Height 类只提供接口。所以这更像是一种可以做的关系。