For comparison:
class Base {};
class Derived : public Base {};
Derived d;
Base* p = &d; // points to a Base that in reality is a derived
Base& b = d; // in this respect, references do not differ...
// and you can get the original type back:
auto dr = static_cast<Derived&>(b); // if you know 100% for sure that b is a Derived
auto dp = dynamic_cast<Derived*>(p); // if p might point to another type; you get
// a null pointer back, if it does
There is absolutely no difference with returning pointers or references to this
/*this
, so yes, you can safely do so.
Edit:
Circle().SetStrokeWidth(16).SetCircleCenter({0, 0})
. SetStrokeWidth returns a reference to Element, so SetCircleCenter is unavailable.
In this case, you are a bit in trouble, though. As lubgr denoted already, you can solve the issue by overriding with co-variant return type – and yes, this would mean that you'd have to override each function separately. Alternatively, you can save all this hassle using CRTP:
template <typename T>
class SomeAppropriateName : public Element
{
public:
T& setStrokeWidth(unsigned int width)
{
Element::setStrokeWidth(width);
return static_cast<T&>(*this);
}
};
class Circle : public SomeAppropriateName<Circle>
{
// the overrides needed are inherited...
};
For this approach, original functions from Element
class need to be non-virtual (thanks @Quentin for the hint; actually an advantage as virtual function calls are more costly...); in the template, the argument (T
, i. e. Circle
) is not yet completely defined (with CRTP pattern) and the compiler wouldn't be able to check if the return type really is co-variant. So actually, we are just shadowing the base class' function.
This is still no disadvantage compared to overriding: The co-variant return type will only be available if the (virtual) function is called on the object directly anyway:
Circle c;
c.setStrokeWidth(7).setCenter();
Element& e = c;
e.setStrokeWidth(7).setCenter(); // fails with both variants, i.e. even if you
// implement co-variant override