如何返回真正的自我类型的子类?

时间:2017-01-11 04:11:57

标签: c++

我希望函数返回其真实类型,即使它在子类中调用。这是测试代码:

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 ++中,有可能吗?

顺便说一下,我不想要template实现,因为它可能会增加代码大小。

4 个答案:

答案 0 :(得分:3)

  

但是在C ++中,有可能吗?

是的,就像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; } 类中添加内容。

如果您不需要虚函数,则只需覆盖(静态)该函数:

template<typename Subclass>
struct AddGetSelf {
    auto getSelf() -> Subclass& {
        return static_cast<Subclass&>(*this);
    }
};

当然,如果您不喜欢复制粘贴该代码,您可以随时创建一个mixin类(CRTP模板):

struct Super : AddGetSelf<Super> {
    using AddGetSelf<Super>::getSelf;

    void testSuper(){};
};

struct Sub : Super, AddGetSelf<Sub> {
    using AddGetSelf<Sub>::getSelf;

    void testSub(){};
};

您可以在类中使用mixin:

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

如果您需要虚拟多态,则可以依赖协变返回类型:

vendor/assets/javascripts

以下是Coliru

的实例

如果您担心二进制大小,请考虑静态链接和链接时间优化。

我建议你尝试两种解决方案并比较二进制大小,因为模板大小的增加可以通过编译器优化来消除,虚拟多态可以阻止编译器进行这些优化。

答案 1 :(得分:1)

我将继续。在c ++中没有方便的机制来执行你想要的。 (方便的意思是避免使用任何样板,Guillaume在answer中提出的IMO选项当然值得探讨。)

必须复制不同案例的代码。在运行时期间无法创建类型和对象,例如在C#中。所以你必须为每种类型都有代码。

你可以通过静态多态来做你想做的事,尽管那些是模板。也许编译器足够聪明,可以优化getSelf的每个副本,毕竟它们都返回相同的指针。但是从语言的角度来看,你必须为每种类型提供一个定义。

有运行时类型信息,但您仍然需要在类型之间if有效地复制代码。

您可以使用RTTI和动态强制转换来实现您的示例纯运行时,但它会有点难看,因为您必须手动转换为引用...而且很危险。

E.g:

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

答案 2 :(得分:1)

  

但是在C ++中,有可能吗?

简短回答是 - 不直接,因为它发生在C#中。
this的类型是指向提供成员函数定义的子对象类型的指针。
也就是说,Super *中的getSelf定义中的SuperSub *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); } 这样的调用 它遵循一个最小的工作示例:

return response($content)
        ->withHeaders([
            'Content-Type' => 'text/xml'
        ]);

答案 3 :(得分:1)

在C ++中,无法在Object-C中完成所需的操作。他们有不同的对象调用模型。见https://github.com/ampproject/amphtml/blob/master/ads/google/csa.md。当您在C ++中调用object时,编译器必须在编译时了解有关成员函数的所有内容。在Object-C中,您不直接调用成员函数,而是向对象发送消息。所以这是运行时绑定。