2

In a base class constructor, I would like the instance a derived class. Can I do something like that?

class InterfaceClass // Final user only sees this class
{ 
    enum class TYPE 
    {
        CHILDONE
    };

public:
    InterfaceClass(TYPE);
    virtual void hello_world() = 0;
    virtual void print_class();
};

class ChildOne : public InterfaceClass 
{
public:
    ChildOne() = default;
    void hello_world();
private:

};

InterfaceClass::InterfaceClass(TYPE type) 
{
    if (type == CHILDONE)
        this = new ChildOne();
    else
        throw "NOT HANDLED";
}

void InterfaceClass::hello_world() {
    std::cout << "Hello world from InterfaceClass" << std::endl;
}

void InterfaceClass::print_class() {
    std::cout << "Not implemented" << std::endl;
}

void ChildOne::hello_world() {
    std::cout << "Hello world from ChildOne" << std::endl;
}

// Final user will see only declaration of InterfaceClass
int main()
{
    InterfaceClass* ic = new InterfaceClass(InterfaceClass::TYPE::CHILDONE);
    ic->hello_world();
}

I would like to build an architecture that behaves like this. But I do not know how to do it properly.

JeJo
  • 30,635
  • 6
  • 49
  • 88
tony_merguez
  • 307
  • 2
  • 11
  • 3
    What is the actual and original problem you need to solve? Why do you think something like this, if it was possible, would solve it? Right now your question is too much of an [XY problem](https://en.wikipedia.org/wiki/XY_problem) for us to be able to give good (or any) answers. Please always ask about the actual and underlying problem directly. – Some programmer dude Jul 28 '23 at 07:56
  • 4
    My best guess would be that you want to have some function that creates (and returns) an object of the correct type (e.g.: using the [factory pattern](https://en.wikipedia.org/wiki/Factory_method_pattern)) – UnholySheep Jul 28 '23 at 07:58
  • Yes, create a static factory function, you can't change the type of an object in a constructor (or at any other time) – Alan Birtles Jul 28 '23 at 07:59
  • The [`this` is a pr-value expression](https://en.cppreference.com/w/cpp/language/this), and cannot be the target of an assignment. Note, howver, `*this` can receive assignement, but only when the appropriate `operator=` member function has been defined in the class. – tbxfreeware Jul 28 '23 at 08:02
  • Your design seems at fault here. And remember, inheritance is an "is a" relationship, so `Child` *is a* `InterfaceClass`. That means you can do `InterfaceClass* interface = new Child;`. The polymorphism of C++ would make sure that it worked as expected, and that `interface->hello_world()` would call `Child::hello_world`. – Some programmer dude Jul 28 '23 at 08:13
  • 1
    A [factory method](https://www.programming-books.io/essential/cpp/factory-pattern-b485de1d7f2746e88ce03f88d0ddf86d) might be what you're looking for. – stefaanv Jul 28 '23 at 08:18
  • A factory method or PIMPL ideom. But you can't do what you described. Object type is static once created – Swift - Friday Pie Jul 28 '23 at 09:00

1 Answers1

5

I would like to instantiate A as a child, depending on an enum given in the constructor [...]

This

this = new ChildOne();

doesn't make any sense. The this pointer is a prvalue, to which you can not assign anything. From the description, it seems you need a factory function that returns the derived class, depending upon the enum TYPE.

#include <memory> // std::unique_ptr

std::unique_ptr<InterfaceClass> InterfaceClass::createInstance(TYPE type) 
{
    switch (type) {
    case TYPE::CHILDONE:
        // use smart pointer instead the raw pointers
        return std::make_unique<ChildOne>();  
    // ... more
    default:
        throw "NOT HANDLED";
    }
}

Additionally, the base InterfaceClass class required a virtual destructor, so that deleting the derived through InterfaceClass class pointers (i.e. std::unique_ptr<InterfaceClass> return in createInstance), acts defined behavior.

In short, you might do

#include <memory>

class InterfaceClass 
{
public:
    enum class TYPE
    {
        CHILD_ONE
        // .... CHILD_TWO 
    };

    virtual ~InterfaceClass() {} // required for defined behavior!
    virtual void hello_world() = 0;
    virtual void print_class() = 0;

    static std::unique_ptr<InterfaceClass> createInstance(TYPE type);
};

class ChildOne : public InterfaceClass 
{
public:
    void hello_world() override; // (Optionally) override the virtual functions
    void print_class() override; // (Optionally) override the virtual functions
}

See a demo in godbolt.org

JeJo
  • 30,635
  • 6
  • 49
  • 88