6

I'm using this member function to get pointer to object:

    virtual Object* Create()
    {
        return new Object();
    }

It's virtual so I can get pointer to derived objects, now I'm doing it like this:

    virtual Object* Create()
    {
        return new Foo();
    }

It is working correctly, but I'd like to do something like this to prevent any mistakes and also to make it easier so I don't have to rewrite that function every time I make new class:

    virtual Object* Create()
    {
        return new this();
    }

I was trying to find how to do this but couldn't find anything useful, maybe it's not possible. I'm using MSVC compiler with C++17

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Michaelt LoL
  • 452
  • 5
  • 10
  • If I understand your question correctly, you want to retrieve the actual (dynamic) type of the object within the definition of `Create` inside the base class. Without the need of overriding `Create`. Am I right? If so, I don't understand why you accepted an answer that actually requires overriding. – Daniel Langr Jul 16 '20 at 10:44
  • 2
    Anyway, you are basically trying to solve the same problem as emerge in _clone pattern_ without _clone_ function overriding. This can be achieved with the help of CRTP; see, e.g., [this article](https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/). – Daniel Langr Jul 16 '20 at 10:49
  • 2
    FYI: [SO: How to implement ICloneable without inviting future object-slicing](https://stackoverflow.com/q/57405375/7478597) (about a somehow similar issue). – Scheff's Cat Jul 16 '20 at 10:50
  • 1
    @DanielLangr mainly I needed to know how to do `new this()`, overriding isn't much problem for me, I just needed to prevent mistakes – Michaelt LoL Jul 16 '20 at 10:58

1 Answers1

10

You can get the type from this pointer as

virtual Object* Create() override
{
    return new std::remove_pointer_t<decltype(this)>;
}

LIVE

PS: Note that you still need to override the member function in every derived class. Depending on your demand, with CRTP you can just implement Create in the base class. E.g.

template <typename Derived>
struct Object {
    Object* Create()
    {
        return new Derived;
    }
    virtual ~Object() {}
};

then

struct Foo : Object<Foo> {};
struct Bar : Object<Bar> {};

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • This would not work, because decltype(this) returns not the derived type. It returns only the declared type of this, which is type class where you defined this method. – Bernd Jul 16 '20 at 10:26
  • @BerndBaumanns Sorry I didn't get what you mean, so in derived class it will refer to the derived class, isn't it? [LIVE](https://wandbox.org/permlink/yCx4G7LsZRiIHWW8) – songyuanyao Jul 16 '20 at 10:32
  • You could do it like here: https://stackoverflow.com/questions/62919503/overriding-a-virtual-function-with-a-covariant-return-type-in-a-template-derived/62920210#62920210 – Bernd Jul 16 '20 at 10:53
  • 1
    No, there is just a single implementation. I think he want's to generate an implementation for every derived class - this is possible via CRTP Pattern – Bernd Jul 16 '20 at 10:56
  • 1
    @BerndBaumanns I got what you meant. Added to the answer. – songyuanyao Jul 16 '20 at 11:18
  • unluckily `Object` can't be `template` so the first solution is much better for me – Michaelt LoL Jul 16 '20 at 12:14
  • 1
    If `Object` is a template, then `Foo` and `Bar` does not have the same base class. Typically, you have a single (non-template) base, and then some templated middle-class derived from it implementing CRTP, such as described [here](https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/). – Daniel Langr Jul 16 '20 at 12:34
  • How can the method return Object* if you use the std::remove_pointer_t trait? – Chris Jul 25 '20 at 22:30
  • 1
    @Chris `decltype(this)` yields type `Object*`, `std::remove_pointer_t` yields type `Object`, then the `return` statement is same as `return new Ojbect;`, i.e. returns `Object*`. – songyuanyao Jul 26 '20 at 02:18