c++polymorphism

c++: method operating on a set of instances including the object self


I have a C++ design which I think is ugly, because it is ambiguous.

I have a set of multiple instances of a certain class A (or an inheriting type), which need to perform a computation. The result depends on all instances in this set.

Since the actual implementation of computation is not known at compile-time (it may use a derived class), it needs to be virtual:

#include <vector>

class A {

public:
    
    virtual int computation(const std::vector<const A*>& many_instances_of_A) const {
        // Perform computation with many_instances_of_A.
        // The order of the instances is not important.
        // All instances of A have to be of the same type.
        return 0; // Replace with actual result
    }
};

// Example usage
int main() {
    A a;
    A b;
    A c;

    std::vector<const A*> some_A_instances = {&a, &b, &c};

    // Call the computation method on one of the instances.
    // Which instance is actually used does not matter.
    // However, at this location we do not know the actual (inheriting) type of A,
    // which prevents us from using a static method
    const auto result = some_A_instances[0]->computation(some_A_instances);

    return 0;
}

The scenario is always the same, which means the some_A_instances always contains the calling object. For this reason, it does not matter which object in some_A_instances is used to perform the computation. Since I need polymorphism, a static method does not work.

How can I improve this design?


Solution

  • If you dislike that it is a member function make it a free function:

    #include <vector>
    
    struct A {
        virtual int compute() const { return 0; }
    };
    
    auto computation(auto begin, auto end) {
        int sum = 0;
        for (; begin != end; ++begin) sum += (*begin)->compute(); 
        return sum;
    }
    
    int main() {
        A a,b,c;   
        std::vector<const A*> some_A_instances = {&a, &b, &c};
        const auto result = computation(some_A_instances.begin(),some_A_instances.end());
    }
    

    Live Demo

    Just because you need something to be a virtual member function that can be overridden by derived classes does not imply that everything must be done in that virtual member function.

    If this refactoring doesn't work, because the part that combines the results of the individual element needs to be virtual, then I agree with what has been said in a comment:

    Sounds like computation is a job for class that will own all these A instances, not for A itself. Without more specific info it's hard to propose any solution. – Yksisarvinen

    How to proceed depends on details you didn't tell us. Design does not emerge out of nothing but from concrete requirements. The questions you need to answer for yourself: Why is computation a member of A? What part of it needs to be customized? What part does not need to be customized? (None of this is clear from your post).