I have a parent class that is designed to be const-safe, so I want to create "factory" methods that will return an altered version of itself in a newly constructed object. I want to be able to return by value and avoid heap allocation, similar in function to std::string::substr
. This works fine in the parent class, but how to I allow a subclass to return override this method to return a covariant type, preferably without pointers or references?
I have a Point
class that is provided to me that represents a 2D position:
class Point
{
double x, y;
public:
Point() : Point(0, 0)
{ }
Point(double xpos, double ypos) : x{xpos}, y{ypos}
{ }
double get_x() const { return x; }
double get_y() const { return y; }
virtual Point flip_x() const
{
return Point{x, -y};
}
virtual Point flip_y() const
{
return Point{-x, y};
}
...
};
Notice that flip_x
and flip_y
are factory methods that return a new flipped Point
object by value. This allows me to do something like const Point flipped = p.flip_x()
without modifying the contents of const Point p
.
I am implementing a subclass to Point
called Point3D
that supports an additional z depth coordinate. I want to be able to override these flip functions to return a Point3D
instead, in order to be consistent with the return type of flip_z
:
class Point3D : public Point
{
double z;
public:
Point3D() : Point3D(0, 0, 0)
{ }
Point3D(double xpos, double ypos, double zpos)
: Point(xpos, ypos), z{zpos}
{ }
double get_z() const { return z; }
// *** ERROR: return type is not covariant ***
Point3D flip_x() const override
{
return Point3D{get_x(), -get_y(), -z};
}
// *** ERROR: return type is not covariant ***
Point3D flip_y() const override
{
return Point3D{-get_x(), get_y(), -z};
}
Point3D flip_z() const
{
return Point3D{-get_x(), -get_y(), z};
}
...
};
So these errors tell me that the return types are not covariant with the parent methods. As far as I can tell, my only options for using covariant returns are to use references or pointers. I cannot return a reference or pointer to a local variable, and using new
to return a heap allocated Point
adds unnecessary complexity to memory management. How can I achieve the effect of returning by value/static binding when returning a covariant type, so that the following is still valid:
const Point p{2, 2};
const Point flipped = p.flip_x(); // (2, -2)
const Point3D p3{2, 2, 2};
const Point3D flipped3 = p3.flip_x(); // (2, -2, -2)
Is this possible using this parent class and within these limitations, or will I have to switch to pointers & heap allocation?
If you remove virtual, you might do:
class Point
{
double x, y;
public:
Point() : Point(0, 0) { }
Point(double xpos, double ypos) : x{xpos}, y{ypos} { }
double get_x() const { return x; }
double get_y() const { return y; }
Point flip_x() const { return Point{x, -y}; }
Point flip_y() const { return Point{-x, y}; }
// ...
};
class Point3D : public Point
{
double z;
public:
Point3D() : Point3D(0, 0, 0) { }
Point3D(double xpos, double ypos, double zpos) : Point(xpos, ypos), z{zpos} {}
double get_z() const { return z; }
// hides parent ones
Point3D flip_x() const { return Point3D{get_x(), -get_y(), -z}; }
Point3D flip_y() const { return Point3D{-get_x(), get_y(), -z}; }
Point3D flip_z() const { return Point3D{-get_x(), -get_y(), z}; }
///...
};