Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return real self type of subclass?

Tags:

c++

I want a function return its real type, even it called in subclass. Here is the test code:

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

In Objective-C, I can use instanttype to solve this.
But in C++, is it possible?

By the way, I do not want a template implementation, since it may increase the code size.

like image 761
Ringo_D Avatar asked Nov 23 '25 08:11

Ringo_D


1 Answers

But in C++, is it possible?

Yes, and just like anything in C++, there is many ways to do it. But both ways require you to add something in the Sub class.

If you don't need virtual functions, then simply override (statically) that function:

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

Of course, if you don't like copy pasting that code, you can always create a mixin class (a CRTP template):

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

You can the use that mixin in your classes like this:

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

    void testSuper(){};
};

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

    void testSub(){};
};

If you need virtual polymorphism, you can rely on covariant return types:

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

Here's a live example at Coliru

If you are worried about binary size, consider static linking and link time optimisation.

I suggest you to try out both solutions and compare binary sizes, since template size increase can be cancelled out by compiler optimisation, and virtual polymorphism can prevent the compiler to do these optimisations.

like image 102
Guillaume Racicot Avatar answered Nov 24 '25 22:11

Guillaume Racicot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!