Jay Iuliano
Jay Iuliano

Reputation: 21

How do you call non-virtual, non-const derived class methods from a unique_ptr to base?

I have a factory pattern that stores a series of different derived classes in a map of unique_ptr to base:

class ForceFactory {
private:

    using BuilderFunc = std::function<std::unique_ptr<Force>()>;
    
    const std::unordered_map<std::string, BuilderFunc> builders = {
        {"DerivedForceA",  build_a},
        {"DerivedForceB",  build_b},
        {"DerivedForceC",  build_c}
    };

    std::unordered_map<std::string, std::unique_ptr<Force>> forces;

public:
    // Build call for pre-defined, derived Forces
    const std::unique_ptr<Force>& build(const std::string& force) {
        if (forces.count(force) == 0) {
            forces[force] = builders.at(force)();
        }
        return forces[force];
    }
};

where the base class is just a container for a virtual method:

class Force {
public:
    Force() = default;
    ~Force() = default;

    virtual std::array<double, 3> compute_force(...) const = 0;
};

And each of the builder functions for non-user-defined derived classes looks like this:

std::unique_ptr<Force> build_derived() { return std::make_unique<DerivedForce>(); }

I have a non-virtual method for setting some options in one of my derived classes that modifies a private, non-virtual member.

class DerivedForce : public Force {
public:
    DerivedForce() = default;
    ~DerivedForce() = default;

    std::array<double, 3> compute_force(...) const override;

    void set_coefficients(...); // modifies _data

private:

    mutable std::vector<std::vector<double>> _data{};
};

I've tried to access the derived class by casting the returned pointer and then calling the method, but it results in a segfault when the method tries to resize _data.

    auto& baseRef = forces.at("DerivedForce");
    auto* basePtr = baseRef.get();
    auto* derivedPtr = dynamic_cast<DerivedForce*>(basePtr); 
    derivedPtr->set_coefficients(...); // segfaults at call to _data.resize(...) 

What is the correct way to call a non-virtual, non-const method on one of the derived classes after it's initialized?

The reason I use this builder paradigm instead of initializing each of the derived classes, and calling any methods like this one before storing them as unique, is that I want any derived classes not defined by users to be built without users having to manually initialize them.

Is this even possible? Will the modifications to the derived class just be sliced away as soon as it's re-casted as its base class? Am I missing the mark here on how/when to use polymorphism? Any guidance would be greatly appreciated.

EDIT:
I've made a couple modifications based on some of the comments. To give some context for those asking, the goal of this is to have a way of storing arbitrary, user-defined Derived classes, while also providing functionality for automatically building any pre-defined Derived classes for the user. The thought was that users would have to initialize their own custom classes and then pass them to the factory to hold and redistribute as needed, but the factory should be able to build anything else on its own.

I'm hesitant to make functions like this virtual on the Base class since they're not necessarily meaningful for all of the Dervied classes, just this one. This functionality could be moved to the constructor of the Derived class, but I'm not sure how I could use a builder paradigm with function signatures that change for each Derived class. Ahmed's comment seems like it has a solution to this problem but I'm not sure I completely understand it.

Upvotes: 0

Views: 95

Answers (0)

Related Questions