Search code examples
c++oopobjectsubclassderived-class

Is it possible to generalize an object type in a helper function?


I have a class CLASS. Classes A and B are derived from CLASS. CLASS, and therefore A and B too, have a field to hold a pointer to an array of pointers to CLASS.

Say I have a member function of A that does some calculations, creating objects of type A throughout. Pointers to these objects are added to the array stored in the object that is calling the function. The function returns void and takes no arguments. In class B, I want to do the exact same calculations, except create objects of type B instead. I am trying to write a helper function that can be called in both locations, creating objects of type A in one place and of type B in the other.

The constructors of the two classes A and B are identical, because they are both derived classes from the same base class. In the class A version function, if object A(x, y, z) is created, I would want the class B version to create B(x, y, z), the constructor taking the exact same arguments it would have in the class A version. This goes for every object that gets created.

class CLASS {
public:
    CLASS** array
    int x, y;
    CLASS(CLASS** arr, int xcoord, int ycoord);
    virtual ~CLASS();
};

class A : public CLASS {
public:
    A(CLASS** arr, int xcoord, int ycoord);
    void foo();
    virtual ~A();
};

class B : public CLASS {
public:
    B(CLASS** arr, int xcoord, int ycoord);
    void foo();
    virtual ~B();
};

//in A.cpp, definition of foo()
void A::foo() {
    int a = some value
    if (some condition) { array[a + 1] = new A(array, (a + 1), y); }
    else if (other condition) { array[a - 1] = new A(array, (a - 1), y); }
    //etc.
}

//in B.cpp, definition of foo()
void B::foo() {
    int a = some value
    if (some condition) { array[a + 1] = new B(array, (a + 1), y); }
    else if (other condition) { array[a - 1] = new B(array, (a - 1), y); }
    //etc.
}

I am not too familiar with template functions, but as far as I understand them they allow you to change the type of the function arguments and the return, which does not seem to be useful here.

Is this possible to do efficiently? I know I can just copy and paste the code and change it to make B objects and have a switch to run one or the other, or just have one version in A and one in B, but I am trying to avoid using either of these methods.


Solution

  • It seems to me that using virtual functions for this would be good. But if you really want to you can get around it with some CRTP.

    If we add a CLASS_IMPL class that holds the helper function and make it derive from CLASS.

    template <typename T>
    class CLASS_IMPL : public CLASS {
        CLASS* makeNew (int x, int y) {
            CLASS* ptr = new T(array, x, y);
            return ptr;
        }
    }
    

    Downside here is that we need to change A and B to use

    class A : public CLASS_IMPL<A> {
    
    class B : public CLASS_IMPL<B> {
    

    Then you can go ahead and change B::foo to use it.

    void B::foo() {
        int a = some value
        if (some condition) { array[a + 1] = makeNew(a + 1, y); }
        else if (other condition) { array[a - 1] = makeNew(a - 1, y); }
        //etc.
    }