How to enforce a static member on derived classes?
我有一个基类,
我的问题出现在以下方面:我希望每个派生实例都能够识别其类型,比如通过
然而,C++中不允许使用静态虚拟方法。C++静态虚拟成员?和我们能有一个虚拟静态方法吗?(C++)问类似的问题,但它们不包括对派生类强制执行函数的要求。
有人能帮我吗?
让我们考虑一下。我敢肯定你不仅有两个子案例,所以让我们概括一下。
首先想到的是代码复制、可扩展性和紧密性。让我们进一步讨论一下:
如果您想添加更多的类,您应该在尽可能少的地方更改代码。
因为
另外,添加一个新的类并不意味着你必须修改现有的类,而是扩展一个委托类(是的,我们将在这里讨论模式)。
我假设这是您当前的结构(或者类似的,可能是
1 2 3 4 5 6 7 8 9 10 11 12 | struct Primitive { virtual void intersect(Primitive* other) = 0; }; struct Sphere : Primitive { virtual void intersect(Primitive* other) }; struct Plane : Primitive { virtual void intersect(Primitive* other); }; |
我们已经决定不希望在
1 2 3 4 5 6 7 | 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&); }; |
这是将要添加新函数和新逻辑的类。例如,如果决定添加一个
记住,添加新类时,我们不想更改现有代码。所以我们不能检查intersect函数中的类型。
我们可以为此(策略模式)创建一个行为类,它的行为因类型而异,然后我们可以进行扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); } }; |
在我们最初的方法中,我们会:
1 2 3 4 5 6 7 8 | struct Sphere : Primitive { virtual void intersect(Primitive* other) { SphereIntersectBehavior intersectBehavior; return intersectBehavior.doIntersect(other); } }; |
更清洁的设计将是实现工厂,以抽象出实际的行为类型:
1 2 3 4 5 6 7 8 | struct Sphere : Primitive { virtual void intersect(Primitive* other) { IntersectBehavior* intersectBehavior = BehaviorFactory::getBehavior(this); return intersectBehavior.doIntersect(other); } }; |
你甚至不需要
如果你按照这个设计
- 添加新类时无需修改现有代码
- 将实现放在一个地方
- 每种新类型仅扩展
IntersectBehavior 。 - 在
intersect 类中为新类型提供实现
我敢打赌这会进一步完善。
由于它们在您提供的链接中讨论的原因,您不能使虚拟成员成为静态的。
关于在派生类上强制函数的要求的问题是通过使抽象基类中的函数纯虚拟来处理的,抽象基类将强制派生类必须实现该函数。
As all instances of the same class will return the same type, it makes sense to make type() a static method.
不,不是。当不需要对象的实例来调用函数时,可以使用静态方法。在本例中,您试图标识对象的类型,因此您确实需要一个实例。
无论如何,所有方法体都由所有对象共享,因此不必担心重复。唯一的例外是当函数是内联的,但是编译器会尽最大努力减少开销,如果开销太大,可能会将其变为非内联的。
P.S.要求类在类层次结构之外标识自己通常是一种糟糕的代码味道。试着找到另一种方法。
您可以让一个非静态虚拟方法调用静态方法(或返回静态字符串),并在每个派生类中适当实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <iostream> #include <string> struct IShape { virtual const std::string& type() const =0; }; struct Square : virtual public IShape { virtual const std::string& type() const { return type_; } static std::string type_; }; std::string Square::type_("square"); int main() { IShape* shape = new Square; std::cout << shape->type() <<" "; } |
请注意,无论如何,您必须为每个子类实现
现在,回到问题的基本面,我认为设计有些缺陷。您不能真正拥有对所有类型形状进行操作的常规交集函数,因为交集产生的形状类型差异很大,即使对于同一类型的形状(例如,两个平面可以在一个平面、一条直线上相交,或者根本不相交)。因此,在尝试提供一个通用的解决方案时,您会发现自己在各地执行这种类型检查,并且随着添加的形状的增加,这种检查将无法修复地增长。