-2

I've been looking at this code for few hours and I can't find why I can't instantiate class. So I have interfaces:

class ICloneable {
    public:
    virtual ICloneable* clone() const = 0;
    virtual ~ICloneable() = 0 {}
};


class IPrintable
{
    protected:
        virtual void print(std::ostream&) const = 0;
    public:
        virtual ~IPrintable() = 0;
        friend std::ostream& operator<<(std::ostream, const IPrintable&);
};
std::ostream& operator<<(std::ostream os, const IPrintable& other) {
    other.print(os);
    return os;
}


class IComparable {
    protected:
        virtual bool is_greater(const IComparable& other) const = 0;
        virtual bool is_equal(const IComparable& other) const = 0;
    public:
        virtual ~IComparable() = 0;
        virtual bool operator>(const IComparable& other) const {
            return is_greater(other);
        }
        virtual bool operator<(const IComparable& other) const {
            return !(is_greater(other) || is_equal(other));
        }
        virtual bool operator==(const IComparable& other) const {
            return is_equal(other);
        }
        virtual bool operator!=(const IComparable& other) const {
            return !(is_equal(other));
        }
};

And I have two classes that inherit these interfaces:

class I2DShape : public IComparable, public IPrintable {
    public:
        virtual void print(std::ostream& os) const override final {
            os << "Circumference: " << this->circumference();
        }
        virtual bool is_greater(const I2DShape& other) const final {
            return this->circumference() > other.circumference();
        }
        virtual bool is_equal(const I2DShape& other) const final {
            return this->circumference() == other.circumference();
        }

        virtual double circumference() const = 0;
        virtual ~I2DShape();
};


class IPositionable : public IPrintable, public IComparable {
    public:
        virtual void print(std::ostream& os) const override final {
            
        }

        virtual bool is_greater(const IPositionable& other) const final {
            distance_from_origin() > other.distance_from_origin();
        }
        virtual bool is_equal(const IPositionable& other) const final {
            distance_from_origin() == other.distance_from_origin();
        }
        
        virtual double distance_from_origin() const {
            return sqrt(pow(center().get_x(), 2) + pow(center().get_y(), 2));
        }
        virtual Point center() const = 0;
        virtual ~IPositionable();
};

And in the final these two classes are inherited by one which represents shape:

class Shape2D : public IPositionable, public I2DShape, public ICloneable {
    protected:
        int num_of_points;
        Point* points;
    public:
        Shape2D() : num_of_points(0), points(nullptr) {}
        Shape2D(int num) : num_of_points(num), points(new Point[num]) {}
        Shape2D(const Shape2D& other) : num_of_points(other.num_of_points) {
            points = new Point[num_of_points];
            for (int i = 0; i < num_of_points; i++) {
                points[i] = other.points[i];
            }
        }
        Shape2D& operator=(const I2DShape& other) {
            
        }
        virtual Shape2D* clone() const override = 0;
        virtual ~Shape2D() {
            if(points)
                delete[] points;
        }
};

When I derive Square from Shape2D and make function for cloning, I get error that it's abstract class:

class Square : public Shape2D {
    private:
        double side;
    public:
        Square() {}
        Square(double s, Point center) : side(s), Shape2D(1) { points[0] = center;}
        
        virtual Point center() const override{
            return points[0];
        }
        virtual double circumference() const override {
            return 4 * side;
        }
        virtual Square* clone() const override final {
            return new Square(*this); //error on this line
        }
};

Error: object of abstract class type "Square" is not allowed

qu4lizz
  • 317
  • 2
  • 12
  • 2
    `virtual ~ICloneable() = 0 {}` isn't valid C++. Your code also can't be compiled since it used undeclared types like `Point`. – Brian61354270 Dec 17 '21 at 20:05
  • For it to be valid, it has to be declared as `... = 0;`, then defined outside of the class body. – HolyBlackCat Dec 17 '21 at 20:07
  • 2
    Clang [gave me](https://gcc.godbolt.org/z/bTc3WMzhW) as list of non-overriden virtual methods. `virtual bool is_greater(const IPositionable& other)` and others don't override the base class methods, because the parameter type is different. The compiler wouldn't told you this if you used `override`. In the future, please attach code in form of a [mcve] - a single piece that we can paste directly into a compiler without adding missing headers or classes. – HolyBlackCat Dec 17 '21 at 20:09
  • `Shape2D` inherits multiple definitions for `is_greater` et. al. from `IPositionable` and `I2DShape`. Which do you expect / want it to use? – Brian61354270 Dec 17 '21 at 20:10
  • @Brian I didn't include `Point` because it's ordinary class. I fixed `virtual ~ICloneable() = 0 {}` but problem still exists. – qu4lizz Dec 17 '21 at 20:36
  • @HolyBlackCat Thanks for advice and finding error. I'm not sure how to fix it so the functionality stays the same. – qu4lizz Dec 17 '21 at 20:38
  • @Brian I want to use both depending on the case. If I want to compare shapes by circumference I would use `IShape2D` and if I want to compare by distance from origin I would use `IPositionable`. Same for `print`. – qu4lizz Dec 17 '21 at 20:40
  • *"not sure how to fix it so the functionality stays the same"* I would get rid of 'printable' and 'comparable' interfaces. You can use [concepts](https://en.cppreference.com/w/cpp/language/constraints) in their place if you want to. – HolyBlackCat Dec 17 '21 at 21:25
  • I've voted to close with a reason "Needs more focus" since there are multiple problems in the code (the invalid syntax for destructor of `ICloneable` as well as pure virtual functions not being overridden). – Peter Dec 18 '21 at 00:34

2 Answers2

0

Since in interfaces you declared destructors with = 0 you are forcing explicit implementation of it in sub-classes which can be instantiated.

There are two ways to fix it.

  • Make interface classes in standard way with default destructors (no = 0), using {} or = default.
  • Add explicit destructor for Square

Note that pure virtual destructor with implementation is treated by gcc and clang as an error.

Related SO questions:

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Thanks for response. I added explicit destructor for `Square` but problem still exists. As @HolyBlackCat stated in the comments, problem is probably with function `is_greater` and `is_equal` because they have different parameters but I'm not sure how to fix it. – qu4lizz Dec 17 '21 at 20:53
  • 1
    @qu4lizz The way to fix the problems with `is_greater()` and `is_equal()` is for `Shape2D` to explicitly override them (i.e. declare them within the class definition with the same arguments as they have in the base class, and define [i.e. implement] them). That won't fix the problem pointed out by Brian though - the syntax for the destructor of `ICloneable` is invalid, and you ALSO need to fix that. – Peter Dec 18 '21 at 00:32
  • like I wrote: if base class has virtual function with `= 0` then subclass must override - it have explicit implementation of given method. – Marek R Dec 18 '21 at 13:14
0

The error was as @HolyBlackCat stated in the comments, with function is_greater and is_equal because they have different parameters when overriden. Simple fix to this was to remove = 0 from those two functions in IComparable so they weren't pure.

qu4lizz
  • 317
  • 2
  • 12