双重分派和模板类 我有一个C++代码,我比较了一个普通的母类派生的不同类, Foo。如果两个类的类型不同,则比较总是false。否则,它会比较特定于类的一些内部数据
我的代码如下所示:双重分派和模板类 我有一个C++代码,我比较了一个普通的母类派生的不同类, Foo。如果两个类的类型不同,则比较总是false。否则,它会比较特定于类的一些内部数据,c++,templates,double-dispatch,C++,Templates,Double Dispatch,我的代码如下所示: class Bar; class Baz; class Foo { public: virtual bool isSame( Foo* ) = 0; virtual bool isSameSpecific( Bar* ){ return false; } virtual bool isSameSpecific( Baz* ){ return false; } }; class Bar : public Foo { public: bool
class Bar;
class Baz;
class Foo
{
public:
virtual bool isSame( Foo* ) = 0;
virtual bool isSameSpecific( Bar* ){ return false; }
virtual bool isSameSpecific( Baz* ){ return false; }
};
class Bar : public Foo
{
public:
bool isSame( Foo* foo){ return foo->isSameSpecific(this); }
bool isSameSpecific( Bar* bar){ return bar->identifier == identifier; }
int identifier;
};
// and the same for Baz...
这非常有效(我认为这是一个双重分派),我可以比较Bar
和Baz
,只需要指向Foo
的指针
但现在问题来了。我必须添加一个模板类:
template< typename T>
class Qux : public Foo
{
//...
};
模板
Qux类:公共食品
{
//...
};
问题是,在Foo
中,我不能为Qux*
声明方法isSameSpecific
,因为它是虚拟的和模板的
问题:有什么简单的方法可以解决这个问题吗?编译器在解析
类Foo
定义时,必须知道的(有限)组是特定于名称的虚拟对象。虚拟机在vtable中都有保留条目。模板Qux
可以被无限次重写,需要在Foo
中使用无限次的虚拟。显然,即使不尝试描述一种定义它们的方法,这也行不通
您可能可以使用typeinfo来做您想做的事情,但它不会与类型多态性一起使用。您是对的,这是双重分派,而且您是对的,不幸的是,方法不能同时是虚拟的和模板的(后者是一个实现问题)
我担心纯粹的设计不可能做到这一点;但是,你可以在Qux
中作弊
template <typename T>
class Qux: public Foo {
virtual bool isSame( Foo* foo ) {
if (Qux* q = dynamic_cast<Qux*>(foo)) {
return *this == *q;
}
return false;
}
}; // class Qux
模板
Qux类:公共食品{
虚拟bool-isame(Foo*Foo){
if(Qux*q=动态_-cast(foo)){
返回*this==*q;
}
返回false;
}
}; // 类群
当然,dynamic\u cast
有点作弊(就像所有针对儿童的演员一样),但是它很管用
注意:isSame
方法可能应该是const
并采用const
参数,也称为虚拟bool isSame(Foo const*Foo)const代码>使用RTTI如何:
#include <typeinfo>
struct Foo
{
virtual ~Foo() { }
virtual bool compare_with_same(Foo const & rhs) = 0;
};
struct Bar : Foo
{
int thing;
virtual bool compare_with_same(Foo const & rhs)
{
assert(dynamic_cast<Bar const *>(&rhs) != nullptr);
return static_cast<Bar const &>(rhs).thing == thing;
}
}
bool operator==(Foo const & lhs Foo const & rhs)
{
return typeid(lhs) == typeid(rhs) && lhs.compare_with_same(rhs);
}
#包括
结构Foo
{
虚拟~Foo(){}
虚拟布尔值与相同值比较(Foo const&rhs)=0;
};
结构栏:Foo
{
智力事物;
虚拟布尔值与相同值进行比较(Foo const和rhs)
{
断言(动态_-cast(&rhs)!=nullptr);
返回静态施法(rhs)。thing==thing;
}
}
布尔运算符==(浮点常量和左浮点常量和右浮点常量)
{
返回typeid(lhs)=typeid(rhs)和&lhs。将_与_相同(rhs)进行比较;
}
或者,您可以将typeid
代码放入每个compare\u中,并使用相同的覆盖。这可能会安全一点。这个问题没有真正的解决方案:您需要
一个isSameSpecific
函数用于
您使用的模板。(换句话说,在Foo
中:
template <typename T>
virtual bool isSameSpecific( Qux<T>* );
因此,如果不同类型表示isame
返回false(通常情况下,如果isame
表示它的外观,则返回false)
例如),您也不需要双重分派:
bool Foo::isSame( Foo const* other ) const
{
return typeid( *this ) == typeid( *other )
&& isSameSpecific( other );
}
派生的isSameSpecific
必须转换
指针,但由于它们保证是相同的
作为此
的类型,这是一种简单而安全的操作
最后:如果类没有值语义(以及
几乎可以肯定的是,如果涉及多态性,
简单到:
bool Foo::isSame( Foo const* other ) const
{
return this == other;
}
也许就够了
然而,所有这些都只适用于像isame
这样的东西。
如果您有其他受影响的功能,则返回
对于我最初所说的。也只制作Foo
类模板,或者为所有需要的Qux
编写不同的isSameSpecific
重载。永远感谢您的评论!模板参数对Foo没有意义,futur类可能有其他模板参数,所以我不想以所有的模板参数结束Foo上可能的模板参数。对于不同的重载,这可能是一个可接受的解决方案,但是T可能有很多种可能性,要编写的重载太多(不是很整洁).看看Andrei Alexandrescu的,特别是图案。@PeterWood很有趣,我来看看!谢谢你的回答!这就是我的想法,这就是每个“虚拟模板”的问题所在方法。Typeinfo是我的默认解决方案,但它不认为它是整洁的。所以,也许解决方案确实改变了我对整洁的定义。谢谢你的答案!你的解决方案可能是我要实现的一个(实际上,我可能在所有相同的方法中做到这一点,并去掉ISAMSimulink)。,除非有更好的主意。是的,演员阵容不符合我的准确定义:-)。对于你的NB:在我的实现中,它实际上是常量,因为它对于理解问题不是必需的,所以我去掉了它。无论如何,谢谢你的建议!一点也不作弊。这里的强制转换对设计不是必需的,只是为了克服语言限制。如果这是一个足够的解决方案,您可以在基类中执行类型检查,并且只有在两种类型相同时才转发到isSameSpecific
。如果isSame
总是返回false
,如果不是,那么在基类中执行检查可能是一个更好的解决方案(即使它涉及RTTI),因为您在基类中强制执行post条件。@JamesKanze:但是会略有不同,因为我提出的解决方案允许将Qux
与K类:公共Qux{}进行比较代码>(无论好坏)。在您的情况下,isSameSpecific
的签名是什么<代码>Foo*
也是吗?@MatthieuM。签名必须使用Foo*
,因为要使覆盖生效,签名
bool Foo::isSame( Foo const* other ) const
{
return typeid( *this ) == typeid( *other )
&& isSameSpecific( other );
}
bool Foo::isSame( Foo const* other ) const
{
return this == other;
}