user2237652
user2237652

Reputation: 41

Overriding binary operators in derived classes

Currently I am working on some algebra problem. I have an (almost abstract) base class from which several classes will be derived. All these classes will contain lists of numbers that are ordered in a lot of very different ways. On the base class I want to define some operators that will be implemented for each of the derived classes. The idea is that once this library is finished, I don't have to care anymore about the intrinsics of the derived class. Once I initialize some derived class, I can refer to it by a reference (or pointer) of base-type and through that access all the derived operations.

I would like to setup rather complex algorithms, based on the operations that were defined on the base class. Therefore I want to be able to access these algorithms only via the base class. In that way it should easily generalize to many types of derived classes. I have understood that this is exactly what object oriented programming is about, so that is why I ended up using C++.

I have setup most of what I want in a way similar to this example (works with g++):

#include <iostream>
class base;
base & gettype(const base&);
class base{
    public:
    int x;
    int type;
    base() = default;
    base(int in){
        this->type=0;
        this->x = in;
    }
    virtual base & operator+= ( const base & other){
        this->x += other.x;
        return *this;
    }
    virtual base & operator+ ( const base & other){
        base & ret = gettype(*this);
        ret += other.x;
        return ret;
    }
    virtual void print(){
        std::cout << "base is: " << x << "\n";
    }
};
class der1:public base{
    public:
    int a;
    der1(){}
    der1(int in){
        this->x = in;
        this->a = 2*in;
        this->type=1;

    }
    base & operator+= ( const base & other){
        std::cout <<"used der add\n";
        const der1 & otherder = static_cast<const der1 &>(other);
        this->x += otherder.x;
        this->a += otherder.a;
        return *this;
    }
    void print(){
        std::cout << "der1 is: " << x << " " << a << "\n";
    }
};
base & gettype(const base & in){
    if(in.type==0){
        return * new base();
    }
    if(in.type==1){
        return * new der1();
    }
}

main(){
    base baseobj(2);
    baseobj.print();
    baseobj += baseobj;
    baseobj.print();
    (baseobj+baseobj).print(); //Answer is right, but there is a memory leak

    der1 derobj(3);
    derobj.print();
    derobj += derobj;
    base * test = new der1(4);
    test->print();
    (*test) += (*test);
    test->print();
    base & test2 = *test;
    test2 += test2;
    test2.print(); //All these print the right answers as well
    delete test; 
}

But there is a memory leak inside this. Whenever I do something like x=x+y, then the memory that is allocated in the gettype function is not freed anymore.

I have read that it is rather uncommon to have an operator+ function return a reference. However, I cannot make this work in a satisfactory manner when operator+ returns by value. The reason is that when it returns by value, it will return an object sliced as base object. When I define derived operator+ functions with covariant types (like in the example below), they are not used, because I only use base type references, not der1.

#include <iostream>
class base{
    public:
    int x;
    base() = default;
    base(int in){
        this->x = in;
    }
    virtual base & operator+= ( const base & other){
        this->x += other.x;
        return *this;
    }
    virtual base operator+ ( const base & other){
        base ret(*this);
        ret += other.x;
        return ret;
    }
    virtual void print(){
        std::cout << "base is: " << x << "\n";
    }
};
class der1:public base{
    public:
    int a;
    der1(int in){
        this->x = in;
        this->a = 2*in;
    }
    der1 & operator+= ( const der1 & other){
        this->x += other.x;
        this->a += other.a;
        return *this;
    }
    der1 operator+ ( const der1 & other){
        der1 ret(*this);
        ret += other.x;
        return ret;
    }
    void print(){
        std::cout << "der1 is: " << x << " " << a << "\n";
    }
};

main(){
    base baseobj(2);
    baseobj.print();
    baseobj += baseobj;
    baseobj.print();
    (baseobj+baseobj).print();  //This all works nicely for the base class

    der1 derobj(3);
    derobj.print();
    base * test = new der1(4);
    test->print(); //derived print function
    base & test2 = *test;
    test2 += test2; //base add function, because argument base&
    test2.print(); //Indeed, wrong answer.

}

So is it possible to create a library that I can use in a manner similar to this:

base & x = getderived(3) // This will return a (reference/pointer to) derived type
base & y = getderived(3)
x +=y;
x = x+3*y;
//And a whole lot of other operations

delete x
delete y // I don't mine some manual memory management

I hope it is clear what I want to achieve. If you think it is impossible, I'm also happy to with that answer, then I know I have to stop looking further. (If there's no solution, I'll keep my current approach and have to work with += like operators, and skip the binary ones. This is not entirely bad)

Upvotes: 2

Views: 179

Answers (1)

bolov
bolov

Reputation: 75755

In C++ you should never use explicit new/delete and you should follow RAII.

If I understood your issue, I would get rid of type and gettype and instead use a virtual clone:

class base
{
public:
    virtual std::unique_ptr<base> clone() const
    {
        return std::make_unique<base>(*this);
    }
};

class derived : public base
{
public:
    std::unique_ptr<base> clone() const override
    {
        return std::make_unique<derived>(*this);
    }
};

Upvotes: 1

Related Questions