C++ 使用c++;导出对象的协方差';s子类型
以下代码按预期生成子类型的对象,但其默认强制转换为指向该子对象的超级指针。谁能告诉我这是为什么C++ 使用c++;导出对象的协方差';s子类型,c++,inheritance,covariance,C++,Inheritance,Covariance,以下代码按预期生成子类型的对象,但其默认强制转换为指向该子对象的超级指针。谁能告诉我这是为什么 class super { virtual super* get_clone() = 0; } class subA : super { sub* get_clone() { return new subA(); }; } class subB : super { sub* get_clone() { return new subB(); }; } subA a; super
class super {
virtual super* get_clone() = 0;
}
class subA : super {
sub* get_clone() { return new subA(); };
}
class subB : super {
sub* get_clone() { return new subB(); };
}
subA a;
super *s = &a;
现在,如果我在gdb中运行s->get_clone(),我会得到:
(gdb)PS->获取克隆()
(超级*)0x7fff7c
我不明白为什么它返回(super*)指针而不是(subA*)指针。我意识到我可以强制转换指针,但我正在尝试根据返回的子类型创建模板化代码
谢谢 编译器无法知道指针在运行时将指向的对象的实际具体类是什么。它只知道指针将指向s的子类的实例
class super
{
public:
virtual super* get_clone() = 0;
};
class subA : public super
{
public:
subA* get_clone()
{
std::cout << "subA::get_clone()\n";
return new subA();
};
};
class subB : public super
{
public:
subB* get_clone()
{
std::cout << "subB::get_clone()\n";
return new subB();
};
};
int main()
{
subA a;
super *s1 = &a;
super* s2 = s1->get_clone();
//subA* s3 = s1->get_clone(); // compile error here; the compiler doesn't know what is the concrete class s points to.
subA* a1 = &a;
subA* a2 = a1->get_clone(); // here it can know that the returned pointer is to subA.
}
class超级
{
公众:
虚拟超级*get_clone()=0;
};
subA类:公共超级
{
公众:
subA*get_clone()
{
std::cout get_clone();//此处出现编译错误;编译器不知道具体类s指向什么。
subA*a1=&a;
subA*a2=a1->get_clone();//这里可以知道返回的指针指向subA。
}
gdb报告的内容是正确的。它正在报告您调用的方法的返回类型。即使虚拟方法的实现具有不同的返回类型,返回值也会“转换”为您调用的方法返回的返回类型
正如在评论中指出的,虚拟方法get_clone()的动态绑定性质
不适用于静态绑定用例。您可能希望执行的任何静态绑定都可以在子类型内完成,通过super接口。您可以使用super提供的一种CRTP样式模板功能来实现这一点:
class超级{
虚拟超级*get_clone()=0;
受保护的:
模板子*获取\克隆\公用(子*){
//...
返回新的子节点;
}
};
subA级:超级{
subA*get_clone(){返回get_clone_common(this);}
};
在上面的示例中,
subA
通过super
提供的模板接口执行静态绑定,您的函数返回指向未定义类型的指针是否是键入错误?“但我试图基于返回的子类型创建模板化代码。”等等,您正在试图在编译时确定运行时将返回的类型?这是不可能的。不知道在编译时,s
总是指向subA
对象。您需要提供更多有关您真正想要完成的任务的详细信息,因为您要求的是这显然是不可能的,但几乎可以肯定的是,有些东西非常接近您所要求的,这是可能的。感谢您解释这样一个事实,即使用虚拟的协方差只相当于动态绑定,这不足以克服静态绑定。这对我来说是有意义的。但我尝试了您的建议,使用CRTP来播放从super返回值,我仍然遇到麻烦。基本上,我在get_clone中使用了gdb,get_clone的返回类型是(subA*),但是get_clone()的返回类型仍然是(super*)。看起来CRPT仍然不会更改原始(super)指针的静态强制转换。super::get_clone()
总是会产生一个超级*
,因为这就是代码所说的它将返回的内容。模板内容发生在get\u clone\u common
中。
class super {
virtual super * get_clone () = 0;
protected:
template <typename SUB> SUB * get_clone_common (SUB *) {
//...
return new SUB;
}
};
class subA : super {
subA * get_clone () { return get_clone_common(this); }
};