为了好玩,我正致力于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”vs“has-a”,以及“赞成组合而非继承”的评论,我有这样的说法:
答案 0 :(得分:6)
在您的场景中,Element可能不应该从Width和Height继承,而是Width和Height应该是element的数据成员。它的构成与is-a相反,因为可以说元素不是宽度或高度,而是由宽度和高度组成(也可能是其他一些东西)。
答案 1 :(得分:2)
元素应继承宽度 ,如果您需要将元素对象用作宽度 1。 Inheritance is not for code reuse
看看boost :: program_options库可能值得一试。我喜欢他们用于注册房产的奇特方式。
答案 2 :(得分:0)
如果我要这样做,我会在Attribute上进行虚拟继承。我认为这不会有什么重要意义,但如果它最终成为问题,那么这将最大限度地减少重复。
答案 3 :(得分:-1)
首先,如果您面临钻石问题,请使用virtual inheritance,即在基类上使用public virtual
而不是public
。
其次,由于有两个实现,因此您的get
- 和set
- 将会执行的操作并不明确。我使用多重继承的唯一时间是扩展纯虚拟类(也就是接口)。这是Java不支持多重继承的一个很好的理由。
第三,更重要的是,这似乎是在面向对象时对继承(“是a”)与聚合(“has a”)的误解之间的典型案例。在确定某个类是否应该继承另一个类时,您可以使用两个非常简单的指南。如果你有继承A类的A类和B类,则句子“A是a B”应该是有意义的。如果“A有一个B”听起来更好,你应该考虑让B成为A的成员。
在你的情况下,句子“元素是高度”和“元素是宽度”真的没有意义。 “元素有高度”非常有意义。