Home > OS >  How to throw an exception if two different derived class objects from the same base class interact w
How to throw an exception if two different derived class objects from the same base class interact w

Time:04-27

I have an abstract base class(X) with A & B derived classes.

I have a class method in X that is inherited by both classes A & B.

I want the method to be able to throw an exception if two different derived class objects interact with each other.

Here is a contrived example:

class Food{
    public:
        int count;
        void combine(Food* a) {
            this->count  = a->count;
        }
};


class Orange : Food {
    public:
        Orange(int x) {
            count = x;
        }
};

class Apple : Food{
    public:
        Apple(int x) {
            count = x;
        }
};


int main() {
    Food* basket_apples = new Apple(5);
    Food* basket_oranges = new Orange(4);
    Food* crate_oranges = new Orange(10);
    crate_oranges.combine(basket_oranges);//should work fine
    crate_oranges.combine(basket_apples); //should produce error
}

A solution I considered is to override the combine method in both derived classes but that violates DRY(Don't repeat yourself).

I want to know if there are any other options to solve this issue.

CodePudding user response:

You can check that in the combine function :

void combine(Food const& a) // You should pass your argument by const ref
{
    assert(typeid(*this) == typeid(a)); // This checks ONLY IN DEBUG !
    this->count  = a.count;
}

If you want to manage the error, use exception or return value :

void combine(Food const& a)
{
    if(typeid(*this) != typeid(a))
      throw std::runtime_error("Invalid combined types");
    this->count  = a.count;
}


int combine(Food const& a)
{
    if(typeid(*this) != typeid(a))
      return 1;
    this->count  = a.count;
    return 0;
}

Maybe you should transfert the counter ?

void combine(Food& a) // Passing by non-const reference
{
    assert(typeid(*this) == typeid(a));
    this->count  = a.count;
    a.count = 0;
}

Note: As said by user17732522, your member function combine should be virtual and the class should better manage the inheritence. I suggest this :

class Food
{
    protected:
        std::size_t count; // You want this value >= 0
    public:
        Food(std::size_t count_) : count(count_) {}
        Food(Food const& f) : count(f.count) {}
        virtual ~Food() {}
        virtual std::string name() const = 0;
        virtual void combine(Food const& a)
        {
            assert(typeid(a) == typeid(*this));
            this->count  = a.count;
        }
};


class Orange : public Food
{
    public:
        Orange(std::size_t x) : Food(x) {}
        Orange(Orange const& o) : Food(o) {}
        virtual ~Orange() {}
        virtual std::string name() const { return "orange"; }
};

class Apple : public Food
{
    public:
        Apple(std::size_t x) : Food(x) {}
        Apple(Apple const& a) : Food(a) {}
        virtual ~Apple() {}
        virtual std::string name() const { return "apple"; }
};
  • Related