An attempt at inheritance (Geometric Shapes) I'm reading through the chapter on inheritance from C++ Primer 5th Edition. It asks

Organize the following type into an inheritance hierarchy:
(b) Geometric primitives (such as box, circle, sphere, cone)
Identify some of the likely virtual functions as well as public and protected
members.

I was hoping this is a suitable arrangement for the organisation of the hierarchy. My line of thinking was:

The most general property of any shape is its dimension. Thus the code could be factored in to having a base class at the top named Shape which would contain this piece of data.

The necessary member functions will change depending on whether I have a 1D, 2D or 3D shape. 2D shapes will require an area and perimeter function, and 3D shapes a surfaceArea and volume function. The operations of these functions will vary depending on the shape. So define abstract base classes corresponding to each dimension with pure-virtual member functions.

Derive classes from the dimension classes corresponding to the final geometric shapes.


My main concern is that maybe the Shape class isn't all that necessary if its only purpose is to hold dimension and the static member pi. A second concern is how to prevent creation of Shape objects, since it only represents a concept and nothing tangible. I'm guessing to do this I would need to define the destructor as pure virtual - although I have not reached this stage of reading.
Shape.h:
#ifndef SHAPE
#define SHAPE

#include &lt;cmath&gt; //sqrt needed

class Shape{
public:
    Shape() = default;
    Shape(unsigned d): dimensions(d) { }
    virtual ~Shape() = default;
private:
    unsigned dimensions = 0;
protected:
    static const double pi;

};





class DimensionOne : public Shape {
public:
    DimensionOne(): Shape(1) { }

    virtual double length() const = 0;
};


class DimensionTwo : public Shape {
public:
    DimensionTwo(): Shape(2) { }

    virtual double perimeter() const = 0;
    virtual double area() const = 0;
};

class DimensionThree : public Shape {
public:
    DimensionThree(): Shape(3) { }

    virtual double surfaceArea() const = 0;
    virtual double volume() const = 0;
};







//2D SHAPES

class Rectangle : public DimensionTwo {
public:
    Rectangle() = default;
    Rectangle(double a): DimensionTwo(), length(a), width(a) { }
    Rectangle(double x, double y): DimensionTwo(), length(x), width(y) { }

    double perimeter() const override { return 2*(length+width); }
    double area() const override { return length*width;}
private:
    double length = 0, width = 0;
};

class Circle : public DimensionTwo {
public:
    Circle() = default;
    Circle(double r): DimensionTwo(), radius(r) { }

    double perimeter() const override { return 2*pi*radius; }
    double area() const override { return pi*radius*radius;}
private:
    double radius = 0;
};




//3D SHAPES

class Box : public DimensionThree {
public:
    Box() = default;
    Box(double a): DimensionThree(), length(a), width(a), height(a) { }
    Box(double x, double y, double z): DimensionThree(), length(x), width(y), height(z) { }

    double surfaceArea() const override { return (2*length*height) + (4*width*height); }
    double volume() const override { return length*width*height;}
private:
    double length = 0, width = 0, height = 0;
};

class Sphere : public DimensionThree {
public:
    Sphere() = default;
    Sphere(double r): DimensionThree(), radius(r) { }

    double surfaceArea() const override { return (4*pi*radius*radius); }
    double volume() const override { return (4*pi*radius*radius*radius)/3;}
private:
    double radius = 0;
};

class Cone: public DimensionThree {
public:
    Cone() = default;
    Cone(double b, double h): DimensionThree(), base(b), height(h) { }

    double surfaceArea() const override { return pi*base*(base + sqrt(base*base + height*height)); }
    double volume() const override { return (pi*base*base*height)/3;}
private:
    double base = 0, height = 0;
};


#endif // SHAPE

Shape.cpp:
#include &quot;Shape.h&quot;

const double Shape::pi = 3.14159;
A second concern is how to prevent creation of Shape objects, since it only represents a concept and nothing tangible. I'm guessing to do this I would need to define the destructor as pure virtual - although I have not reached this stage of reading.


Yep:

class Shape{
public:
    virtual ~Shape() = 0;
};
Shape::~Shape() {}


Now you can't create objects of Shape.