0

I want to have some nice linear algebra in my code with the help of operator overloading. E.g. a product with a vector and a scalar looks like vec * scalar and returns a vector. The problem is, i have 2D and 3D vectors and at compile time is is not know which one it will be.

My attempt was a empty base class and a derived class for 2D and 3D. However it seems like this is not working as expected because it is not calling the correct methods.

#include <cstdlib>
#include <iostream>

class baseVector {
public:
    baseVector() {}
    ~baseVector() {}
    virtual void print() {
        std::cout << "This is not the vector you are looking for" << std::endl;
    }
    virtual baseVector operator*(const double r) const {}
};

class Vector2 : public baseVector {
public:
    Vector2() {}
    Vector2(double x, double y) {
        data_[0] = x;
        data_[1] = y;
    }

    ~Vector2() {}

    void print() {
        std::cout << data_[0] << ", " << data_[1] << std::endl;
    }

    /** Product: Vector * Scalar */
    baseVector operator*(const double r) const {
        Vector2 result(data_[0]*r,
                       data_[1]*r);
        return result;
    }

private:
    double data_[2];
};


int main(int argc, char** argv) {
    // Construct vector of derived type which is not known at compile time
    baseVector * myVec = new Vector2(1, 2);
    const double val = 5;

    baseVector & tempVec = *myVec;
    tempVec.print();

    // Some nice linear algebra here, can't use datatype Vector 2 because it is know known at compile time
    baseVector resVec = tempVec * val;

    // This should print 5, 10
    resVec.print();
    return 0;
}

I expect resVec to be a vector of type Vector2 with the values 5, 10. Instead it calls the print function of the base class. I understand somehow why this is happening but how do I achiev what I want?

Anyway, is this even the right way to go? Thanks in advance for every hint.

Edit: Slicing is not the answer but explains why it doesn't work. I've found a possible solution with the auto keyword. Skip the inheritance and use auto in the main instead of a specific type. Thanks everyone to make me thinking.

nopech
  • 19
  • 4
  • 3
    Not an answer to your specific question, but you would have a much easier time if you ditch inheritance altogether for this. –  May 27 '19 at 15:44
  • completely agree with Frank. I have seen both Vector3D inheriting from Vector2D and the other way around. Either way its a bit messy, because neither is a Vector3D a Vector2D nor the other way around. – 463035818_is_not_an_ai May 27 '19 at 15:56
  • `delete myVec` -- If you were to do this, undefined behavior would occur due the lack of a virtual destructor in the base class. – PaulMcKenzie May 27 '19 at 16:03
  • "and at compile time is is not know which one it will be." This is not a design I would personally trust tbh, in any programming language. In C++ your baseVector class should be abstract. "Oh but then it won't compile". That's just one piece of evidence against your design, and you are trying to sweep it under the rug by making the class concrete. Tell you what, it's still there under the rug. – n. m. could be an AI May 27 '19 at 16:23
  • If i ditch inheritance, how do i achiev support for 2D and 3D in my linear algebra withouth the need of implementing it twice? – nopech May 27 '19 at 16:28
  • Anyway, even if you fix the immediate problem of returning a logically-abstract `baseVector` by e.g. returning a `shared_ptr`, you will quickly discover that tall the *really* nice linear algebra (i.e. anything that involves two or more vectors) is rather problematic. My recommendation is to avoid inheritance in this application. – n. m. could be an AI May 27 '19 at 16:28
  • 1
    Templates. Learn them, love them. – n. m. could be an AI May 27 '19 at 16:29
  • Oh and your base class as shown has zero lines of code reused by the derived classs. – n. m. could be an AI May 27 '19 at 16:35
  • I know i'm not reusing code from inheritance. The idea was just to use the base class as a type placeholder for Vector2 and Vector3. – nopech May 27 '19 at 16:37
  • Can you explain a little bit more how Templates can be used to solve my problem? I don't see it right now – nopech May 27 '19 at 16:38
  • @nopech -- There are plenty of linear algebra libraries written for C++ that are template-based, [like Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page). Why not see how they work? In addition, what if the type that the user wants to use is not `double`? How are you going to accommodate that, since you've hard-coded `double` as the type used? What if there is a fixed floating point type that has all of the operations available (like `*`), and I want to use that as the type in the vectors? That's one reason to use templates. – PaulMcKenzie May 27 '19 at 18:00

1 Answers1

0

To recap why Vector2::print is not called: resVec is not an instance of Vector2. The concrete i.e. most derived type of resVec is baseVector.

A solution is to give up on your attempt at an abstract interface and instead only provide the function in the derived class. You may want to implement it as a non-member function in order to support val * tempVec:

class Vector2 {
    // ...
    friend Vector2
    operator*(const Vector2& v, double r) {
        return {
            v.data_[0]*r,
            v.data_[1]*r,
        };
    }
    friend Vector2
    operator*(double r, const Vector2& v) {
        return {
            v.data_[0]*r,
            v.data_[1]*r,
        };
    }
};

A modifying function virtual baseVector& baseVector::operator*=(double r) would be another possible approach.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thank you for your time. How does your suggestion prevent me from writing my linear algebra code in main() twice, for 2D and 3D? – nopech May 27 '19 at 16:35
  • @nopech It's unclear what you mean. I don't think my suggestion prevents you from writing your linear algebra code twice. – eerorika May 27 '19 at 16:48
  • I'm sorry if it's not clear. The only reason I used inheritance is to have a "common" type for Vector2 and Vector3 (which I didn't include in the code). Obviously this doesn't work and i'm looking for solutions to have linear algebra in the main() which works for Vector2 and Vector3 so I don't have to write the algorithms I want to implement twice. Nevermind, thank you anyway. – nopech May 27 '19 at 16:57