问题描述
我的课程是
-
基本
-
Derived_A
-
Derived_B
Base
Derived_A
Derived_B
-
Child_One
-
Child_Two
Child_One
Child_Two
Base有两个签名函数:
Base has two signature functions:
virtual void foo( const Parent& ) = 0; virtual void bar( const Base& ) = 0;
程序的其他部分。
问题是:
Derived_A
处理Child_One
和Child_Two
相同。但是Derived_B
对它们的处理方式不同。Derived_A
treatsChild_One
andChild_Two
the same. ButDerived_B
treats them differently.我应该如何实现?
一种方法是找出传递给
Derived_B.foo
的对象类型。这显然是设计缺陷。
我尝试的另一种方法是更改签名函数为:One way is to find out what kind of object is passed to
Derived_B.foo
. This would be apparently "a design flaw".The other way I tried is to change the signature functions as:class Base { class Derived_A; class Derived_B; // virtual void bar( const Base& ) = 0; virtual void bar( const Derived_A& ) = 0; virtual void bar( const Derived_B& ) = 0; } class Derived_A: public virtual Base { virtual void foo( const Parent& ) = 0; } class Derived_B: public virtual Base { virtual void foo( const Child_A& ) = 0; virtual void foo( const Child_B& ) = 0; }
但现在
>函数不能使用
Base.foo
。所以我必须写bar
函数两次,虽然代码是完全一样的。But now the
bar
function cannot useBase.foo
. So I have to write thebar
function twice, although the code is exactly the same.处理问题的方法?你建议哪一个?
Are there any other ways to deal with the problem? which one do you suggest?
我想不出一个好的称号。请随时修改它。
P.S. I couldn't think of a good title. Please feel free to modify it.
推荐答案
没有两个类型层次结构之间的关系的详细信息, ,不可能说什么方法是适当的。我对其他答案和另一个可行的替代方法进行了概述,可以扩展到在注释中提到的访问者模式。
Without details of what the two type hierarchies' relation is with each other and how they interact, it's impossible to say what approach is appropriate. I've composed an overview of the other answers and another viable alternative that can be extended to the visitor pattern which was mentioned in a comment.
执行多态行为正如Joey Andres所建议的,在
Parent
中实现virtual
函数的子程序是此问题的典型面向对象解决方案。是否适当取决于对象的责任。Performing the polymorphic behaviour in the children implementing a
virtual
function inParent
as already suggested by Joey Andres is quite typical object oriented solution for this problem in general. Whether it's appropriate, depends on the responsibilities of the objects.Olayinka建议的类型检测,在你的问题中已经提到,肯定会闻到kludgy,但是根据细节,是最小的邪恶。它可以用成员函数返回一个
枚举
(我想这是Olayinka的答案试图表示)或一系列的dynamic_cast
,如中的答案之一所示。The type detection as suggested by Olayinka and already mentioned in your question certainly smells kludgy, but depending on details, can be the minimum of N evils. It can be implemented with member function returning an
enum
(I guess that's what Olayinka's answer tries to represent) or with a series ofdynamic_cast
s as shown in one of the answers in the question you linked.一个简单的解决方案可能是重载
中的
:foo
基本A trivial solution could be to overload
foo
inBase
:struct Base { virtual void foo(const Parent&) = 0; virtual void foo(const Child_Two&) = 0; }; struct Derived_A: Base { void foo(const Parent& p) { // treat same } void foo(const Child_Two& p) { foo(static_cast<Parent&>(p)); } }; struct Derived_A: Base { void foo(const Parent& p) { // treat Child_One (and other) } void foo(const Child_Two& p) { // treat Child_Two } };
如果还有其他子类型
Base
$Child_One
和Child_Two
同样,然后执行foo(const Child_Two& / code>可以放在
Base
中以避免重复。If there are other subtypes of
Base
that treatChild_One
andChild_Two
the same, then the implementation offoo(const Child_Two&)
may be put inBase
to avoid duplication.foo
必须使用适当的静态类型的引用来调用。该调用不会基于动态类型解析。这可能会更好或更糟的你的设计。如果你需要多态行为,你可以使用访问者模式,基本上在上面的解决方案上添加虚拟分派:The catch of this approach is that
foo
must be called with a reference of proper static type. The call will not resolve based on the dynamic type. That may be better or worse for your design. If you need polymorphic behaviour, you can use the visitor pattern which essentially adds virtual dispatch on top of the solution above:struct Base { foo(Parent& p) { p.accept(*this); } virtual void visit(Child_A&) = 0; virtual void visit(Child_B&) = 0; }; struct Parent { virtual void accept(Base&) = 0; }; struct Child_A: Parent { void accept(Base& v) { v.visit(*this); } }; // Child_B similarly struct Derived_A: Base { void treat_same(Parent&) { // ... } void visit(Child_A& a) { treat_same(a); } void visit(Child_B& b) { treat_same(b); } }; struct Derived_B: Base { void visit(Child_A&) { // ... } void visit(Child_B&) { // ... } };
有更多的样板,但是因为你似乎很反对在孩子们实现行为,可能是你的好方法。
There's a bit more boilerplate, but since you seem very averse to implementing the behaviour in the children, this may be good approach for you.
这篇关于类设计并发症(C ++)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
-