假设我有一个类结构(简化我的实际类):
class Graph
{
};
class DerivedGraph : public Graph
{
};
class DerivedGraph2 : public Graph
{
};
我想扩展此结构以考虑同一图表的不同变体。理想情况下,我希望能够做到这样的事情:
class Graph
{
};
// Removed
//class DerivedGraph : public Graph
//{
//};
// Removed
//class DerivedGraph2 : public Graph
//{
//};
class DerivedGraph3 : public Graph // really just a mode of DerivedGraph
{
};
class DerivedGraph4 : public Graph // really just a second mode of DerivedGraph
{
};
class DerivedGraph5 : public Graph // really just a mode of DerivedGraph2
{
};
class DerivedGraph6 : public Graph // really just a second mode of DerivedGraph2
{
};
但是你可以在这里快速看到问题 - 我必须在这里创建太多的类。此外,基类非常复杂和庞大(底线是它很简单)...所以我不想做太多结构上的改变。我希望在图形本身的层面上灵活地定义事物,但同时具有为一种图形类型的特定模式定义事物的灵活性。我希望能够使用诸如DoesGraphSupportNormalizedData()之类的虚函数或类似的东西(这只是一个简单的例子)。然后每个类都会覆盖此方法。
我的另一个想法是为模式本身创建一个单独的类结构(Graph类将创建它的实例),如:
class BaseMode
{
};
class Mode1 : public BaseMode
{
};
class Mode2 : public BaseMode
{
};
现在的问题是这些模式类需要访问Graph类中的几个数据......我真的不想传递所有这些信息。模式类将变得无用,根本不灵活。我只是想不出一个干净的方式来处理这个问题。我能想到的最好的方法是让模式类尽其所能,而不必将所有类型的垃圾传递给它,但现在界面只是愚蠢和笨拙。有什么想法吗?
答案 0 :(得分:0)
您可以使用用户和界面,也可以使用我从描述中收集的继承类。
如果您使用基类并继承它,只需要让您不希望派生类的内容只是为它们提供private
访问修饰符,然后protected
或{{1其他人(视情况而定)。这样,派生类只会获取所需的信息。您还可以拥有一个需要在每个较低类中设置的实例变量,以定义每个派生类的内容。访问修饰符是你的朋友。
如果您使用界面,只需包含每个图形所需的所有内容,然后在构建单个类时,只需从中定制它们以包含特色。
如果这取决于我,就个人而言,我会继续通过界面,但那只是我。
答案 1 :(得分:0)
之前我遇到过这种问题(现在还是......)
在这种情况下,你可能会采取错误的方式,你正在研究的是设备是一种专门的功能,具体取决于图形和模式的类型。继承很好,但它有其限制,如你所提到的。特别是因为用户可能想要切换图形的类型,但保留现有的图形对象。在这种情况下,继承没有帮助。
执行此类操作的一种方法是创建根据当前类型和模式调用的函数。假设您必须绘制线条,并且模式可以设置为LINE或DOTS。您可以使用两个绘制线条的函数,这些函数特定于模式或其他模式:
void Graph::draw_line_line(line l)
{
// draw a line
}
void Graph::draw_line_dots(line l)
{
// draw a dots along the line
}
现在,您可以定义一种表示该类型的渲染函数的类型及其变量成员:
typedef void (Graph::*draw_line_func)(line l);
draw_line_func m_draw_line;
有了这个,您可以编写set_mode()函数,如下所示:
void Graph::set_mode(mode_t mode)
{
m_mode = mode; // save for get_mode() to work
switch(mode)
{
case LINE:
m_draw_line = &Draw::draw_line_line;
break;
case DOTS:
m_draw_line = &Draw::draw_line_dots;
break;
...
}
}
现在当你想渲染这条线时,你会调用这个专门的函数,你不需要知道它是LINE还是DOTS ......
void Graph::draw_line(line l)
{
this->*m_draw_line(l);
}
通过这种方式,您可以创建一个间接,并在现有的具有大型开关或许多if()语句的大型函数中使其更加清晰,而不会破坏许多可能难以使用的现有“强大”类(因为如果它那么大它可能已经在使用......)