我有一个基类 Primitive
,我从中派生了几个其他类 -- Sphere
、Plane
等。
Primitive
通过纯虚函数在其子类上强制执行某些功能,例如 intersect()
。 intersect
的计算依赖于实例数据,因此将其作为成员方法是有意义的。
我的问题出现在以下方面:
我希望每个派生实例都能够识别其类型,比如通过 std::string type()
成员方法。由于同一类的所有实例都将返回相同的类型,因此将 type()
设为 static
方法是有意义的。因为我也希望每个 Primitive
子类都实现这个方法,所以我也想把它变成一个纯虚函数,就像上面的 intersect()
一样。
但是,C++ 中不允许使用静态虚方法。 C++ static virtual members? 和 Can we have a virtual static method ? (c++) 问类似的问题,但它们不包括在派生类上强制执行该功能的要求。
谁能帮我解决以上问题?
最佳答案
让我们考虑一下。我确定您不仅有 2 个 sublcasses,所以让我们概括一下。
首先想到的是代码重复、可扩展性和封闭性。让我们展开这些:
如果您想添加更多的类,您应该在尽可能少的地方更改代码。
因为intersect
操作是可交换的,A
和B
相交的代码应该在同一个place 作为 B
和 A
相交的代码,因此将逻辑保留在类本身中是不可能的。
另外,添加一个新类并不意味着您必须修改现有类,而是扩展一个委托(delegate)类(是的,我们将在这里讨论模式)。
这是你当前的结构,我假设(或类似的,可能是 intersect
的返回类型,但现在不重要):
struct Primitive
{
virtual void intersect(Primitive* other) = 0;
};
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
};
struct Plane : Primitive
{
virtual void intersect(Primitive* other);
};
我们已经决定不希望在 Plane
或 Sphere
中使用相交逻辑,因此我们创建了一个新的 class
:
struct Intersect
{
static void intersect(const Sphere&, const Plane&);
//this again with the parameters inversed, which just takes this
static void intersect(const Sphere&, const Sphere&);
static void intersect(const Plane&, const Plane&);
};
这是您要添加新功能和新逻辑的类。例如,如果您决定添加一个 Line
类,您只需添加方法 intersec(const Line&,...)
。
请记住,在添加新类时,我们不想更改现有代码。所以我们无法检查您的相交函数中的类型。
我们可以为此创建一个行为类(策略模式),它的行为因类型而异,之后我们可以扩展:
struct IntersectBehavior
{
Primitive* object;
virtual void doIntersect(Primitive* other) = 0;
};
struct SphereIntersectBehavior : IntersectBehavior
{
virtual void doIntersect(Primitive* other)
{
//we already know object is a Sphere
Sphere& obj1 = (Sphere&)*object;
if ( dynamic_cast<Sphere*>(other) )
return Intersect::intersect(obj1, (Sphere&) *other);
if ( dynamic_cast<Plane*>(other) )
return Intersect::intersect(obj1, (Plane&) *other);
//finally, if no conditions were met, call intersect on other
return other->intersect(object);
}
};
在我们原来的方法中,我们有:
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
{
SphereIntersectBehavior intersectBehavior;
return intersectBehavior.doIntersect(other);
}
};
一个更简洁的设计是实现一个工厂,以抽象出行为的实际类型:
struct Sphere : Primitive
{
virtual void intersect(Primitive* other)
{
IntersectBehavior* intersectBehavior = BehaviorFactory::getBehavior(this);
return intersectBehavior.doIntersect(other);
}
};
而且您甚至不需要 intersect
是虚拟的,因为它会为每个类都这样做。
如果你遵循这个设计
- 添加新类时无需修改现有代码
- 将实现集中在一个地方
- 仅为每个新类型扩展
IntersectBehavior
- 在
Intersect
类中为新类型提供实现
我敢打赌这可以进一步完善。
关于c++ - 如何在派生类上强制使用静态成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10502114/