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);
}