Appearance
Covariant Return Types
When overriding a virtual function, the return type of the derived class can be a derived type of the base class return type — instead of being exactly the same.
Normal override rule: return type must be identical. Covariant exception: return type can be a derived class pointer/reference.
Problem Without Covariance
cpp
class Dog : public Animal {
public:
Animal* create() override { // forced to return Animal*
return new Dog(); // creates Dog but caller gets Animal* back
}
};
// Caller has to manually cast to use Dog featuresSolution — Covariant Return Type
cpp
class Dog : public Animal {
public:
Dog* create() override { // return Dog* instead of Animal*
return new Dog();
}
};
Dog d;
Dog* dog = d.create(); // get Dog* directly — no cast needed!Real World Example
cpp
class Document {
public:
virtual Document* clone() { return new Document(*this); }
void open() { /* ... */ }
};
class SpreadSheet : public Document {
public:
SpreadSheet* clone() override { return new SpreadSheet(*this); }
void calculate() { /* ... */ }
};
SpreadSheet s1;
SpreadSheet* s2 = s1.clone(); // no cast needed
s2->calculate(); // can directly use SpreadSheet methodRules for Covariant Return Types
cpp
// VALID — pointer to derived class
class Base { virtual Base* get(); };
class Derived { Derived* get() override; };
// VALID — reference to derived class
class Base { virtual Base& get(); };
class Derived { Derived& get() override; };
// INVALID — plain types (not pointer/reference) → ERROR
// INVALID — unrelated types → ERROR
// INVALID — non-derived pointer → ERRORWithout vs With Covariance
cpp
// WITHOUT — ugly cast needed
Dog* dog = dynamic_cast<Dog*>(d.create()); // manual cast, unsafe
// WITH — clean and safe
Dog* dog = d.create(); // direct, type-safeKey Rules Summary
| Rule | Detail |
|---|---|
| Must be | Pointer or reference |
| Return type | Derived of base return type |
| Function must be | virtual in base |
| Plain types | Not allowed |
| Common use case | clone() pattern |
One-liner: "Covariant return types allow an overriding function in a derived class to return a pointer or reference to a more derived type than the base class virtual function, avoiding manual casting."