C++ 如何返回子类的真实自我类型?
我想要一个函数返回它的真实类型,即使它在子类中被调用。以下是测试代码:C++ 如何返回子类的真实自我类型?,c++,C++,我想要一个函数返回它的真实类型,即使它在子类中被调用。以下是测试代码: class Super { public: Super(){}; virtual auto getSelf() -> decltype(*this)& { return *this; } void testSuper(){}; }; class Sub : public Super { public: void testSub(){}; };
class Super
{
public:
Super(){};
virtual auto getSelf() -> decltype(*this)&
{
return *this;
}
void testSuper(){};
};
class Sub : public Super
{
public:
void testSub(){};
};
int main()
{
Sub().getSelf().testSuper();//OK
//Sub().getSelf().testSub();//Error
return 0;
}
在Objective-C中,我可以使用instanttype
来解决这个问题。但是在C++中,有可能吗?< /P> 顺便说一下,我不想要
模板
实现,因为它可能会增加代码大小
<>但是在C++中,有可能吗?< /P>
<>是的,就像C++中的任何东西一样,有很多方法可以做到。但这两种方法都要求您在子类中添加一些内容
如果不需要虚拟函数,则只需(静态)重写该函数:
struct Super {
auto getSelf() -> Super& {
return *this;
}
void testSuper(){};
};
struct Sub : Super {
auto getSelf() -> Sub& {
return *this;
}
void testSub(){};
};
int main() {
Sub().getSelf().testSuper(); //OK
Sub().getSelf().testSub(); //OK too!
return 0;
}
当然,如果您不喜欢复制粘贴该代码,您可以创建一个mixin类(CRTP模板):
这里有一个在
如果您担心二进制大小,请考虑静态链接和链接时间优化。
我建议您尝试这两种解决方案并比较二进制大小,因为模板大小的增加可以通过编译器优化来抵消,而虚拟多态性可以阻止编译器进行这些优化。我将继续使用否。C++中没有方便的机制来执行你的愿望。(所谓方便,我的意思是避免任何样板,纪尧姆在其著作中提出的IMO选项当然值得探索。)
不同情况下的代码必须重复。不能在运行时创建类型和对象,例如在C#中。所以每种类型都必须有代码
通过静态多态性,您可以随心所欲,尽管这些都是模板。也许编译器足够聪明,可以优化getSelf
的每个副本,毕竟它都返回相同的指针。但从语言的角度来看,您必须为每种类型提供定义
有运行时类型信息,但如果类型之间存在有效的代码复制,则仍然需要if
您可以使用RTTI和dynamic cast实现您的示例纯运行时,但这会有点难看,因为您必须手动将其转换为引用。。。而且很危险
例如:
#包括
超级班
{
公众:
超级(){};
虚拟自动getSelf()->decltype(*this)&
{
归还*这个;
}
void testSuper(){};
};
组别分组:公共超级
{
公众:
void testSub(){std::cout
<>但是在C++中,有可能吗?< /P>
简短的回答是-不像在C#中那样直接。
此
的类型是指向提供成员函数定义的子对象类型的指针之一。
也就是说,Super*
中的getSelf
定义在Super
中,Sub*
中的getSelf
定义在Sub
中
也就是说,请注意双重分派的目标符合您的要求。
缺点是像Sub().getSelf().method();
这样的调用在这种情况下不再可能了。
下面是一个简单的工作示例:
struct Visitor;
struct Super
{
virtual void getSelf(Visitor &) = 0;
void testSuper(){}
};
struct Sub : Super
{
void getSelf(Visitor &) override;
void testSub(){}
};
struct Visitor
{
void accept(Sub &sub)
{
sub.testSuper();
sub.testSub();
}
};
void Sub::getSelf(Visitor &v)
{
v.accept(*this);
}
int main()
{
Visitor visitor;
Sub sub;
Super &super = sub;
super.getSelf(visitor);
}
<>你想在Objc中做什么,在C++中是不可能的。它们有不同的对象调用模型。参见。在C++中调用对象时,编译器必须知道编译时成员函数的所有内容。在Objic C中,你不直接调用成员函数,将消息发送给对象。因此这是运行时绑定。hey有时是解决这个问题的最佳解决方案。@GuillaumeRacicot编译器将为所有模板类型生成代码,这会增加代码大小。为什么不投票?问这个问题有错吗?它会使你的函数更快,编译器甚至可以在使用时完全优化你的类模板。不要对你的代码进行过早的优化。@GuillaumeRacicot这不是过早的,这实际上是我的问题。不要猜你不知道什么,只要解决问题本身。哈哈,有趣的是,两个答案相隔2分钟,一个说“是”,另一个说“否”.Ima仍然说OP想要什么是不可能的。不过,你提供了很好且有趣的解决方法。嗯……它们是聪明地忽略了需求的解决方案,值得探索。实际上,这两个都不是完美的解决方案。1和3是一种复制和粘贴。2也是模板。但这是另一种想法,谢谢你您的答案。@Ringo_D实际上,解决方案2与1相同,但没有手动复制粘贴。在“默认”情况下,这是正确的,但虚拟函数是运行时绑定。是的,没错。但是没有类型转换(静态或动态)您无法访问源类型中缺少的非虚拟成员函数。虚拟函数似乎是一种解决方案,但您无法更改其结果类型。因此,您需要动态类型检查和类型转换。它不像Object-C中那样简单,而是一种变通方法。
struct Super : AddGetSelf<Super> {
using AddGetSelf<Super>::getSelf;
void testSuper(){};
};
struct Sub : Super, AddGetSelf<Sub> {
using AddGetSelf<Sub>::getSelf;
void testSub(){};
};
struct Super {
virtual auto getSelf() -> Super& {
return *this;
}
void testSuper(){};
};
struct Sub : Super {
auto getSelf() -> Sub& override {
return *this;
}
void testSub(){};
};
int main() {
Sub().getSelf().testSuper(); //OK
Sub().getSelf().testSub(); //OK too!
return 0;
}
#include <iostream>
class Super
{
public:
Super(){};
virtual auto getSelf() -> decltype(*this)&
{
return *this;
}
void testSuper(){};
};
class Sub : public Super
{
public:
void testSub(){std::cout << "test\n"; };
};
int main()
{
Sub().getSelf().testSuper();//OK
dynamic_cast<Sub&>(Sub().getSelf()).testSub();//Danger
return 0;
}
struct Visitor;
struct Super
{
virtual void getSelf(Visitor &) = 0;
void testSuper(){}
};
struct Sub : Super
{
void getSelf(Visitor &) override;
void testSub(){}
};
struct Visitor
{
void accept(Sub &sub)
{
sub.testSuper();
sub.testSub();
}
};
void Sub::getSelf(Visitor &v)
{
v.accept(*this);
}
int main()
{
Visitor visitor;
Sub sub;
Super &super = sub;
super.getSelf(visitor);
}