Reputation: 14114
I try to override the base class function but because I have templatised its child/derived/sub class I can't override the function depending on which type I instantiate the template with.
struct BaseType
{
virtual double getPropertyValue() = 0;
};
template <typename T>
struct NumberType : BaseType
{
T propertyValue;
T getPropertyValue() override { return propertyValue; } // I would like this to return whatever T is.
};
int main()
{
std::vector<BaseType*> vectr;
NumberType<double> doubleType; // This is fine, overrides the base function
NumberType<int> intType; // Has no overrider, won't compile
}
So I thought maybe I could templatise also the Base class, so that the base class function returns T also. But if I do this I won't be able to keep them in a container or point to them, because they'll all be of different Base< type> types.
I also thought about templatising Base and having it inherit from an even higher parent (which isn't templatised), but I run into the same problem.
Is there any way around this?
Upvotes: 0
Views: 152
Reputation: 120021
BaseType
has a contract that is binding for all its descendants. It says says that getPropertyValue
returns double
. NumberType
doesn't get to modify the contract, it's set in stone.
Let's pretend the contract is not there.
BaseType& base = BaseContainer.getSome();
// base can be NumberType<complex> or
// or NumberType<tensor<double,4,4,4>> or NumberType<padic<5>>
// or a type that is not even thought of yet
// as of now.
what = base.getPropertyValue(); // how should 'what' be declared?
There's no way to use the result of base.getPropertyValue()
if we don't know what it is.
Making the return type covariant doesn't really help. It just shifts the problem from BaseType
to whatever base class BaseType::getPropertyValue()
returns.
You need to come up with a usable interface of BaseType
and stick to it in all descendant classes.
Upvotes: 2
Reputation: 234785
You can do this if the return value T
is covariant with the return value of the pure virtual function. But sadly a T
will not, in general, be covariant with a double
.
Accepting that you're mixing up static and dynamic polymorphism techniques, which might be a design flaw, you could define
struct Cov {};
with
struct BaseType
{
virtual Cov& getPropertyValue() = 0;
};
Then,
template <typename T>
struct NumberType : BaseType
{
T propertyValue;
T& getPropertyValue() override { return propertyValue; }
};
where T
is a child class of Cov
: this relationship means that T&
is a return type that's covariant with Cov&
, and so compilation will succeed. Doing it this way also obviates a value copy of T
being taken. You might also find it convenient to build conversion operators for the various T
s that end up getting built that have primitive type return values.
You can also introduce const
reference return types to suit the exact requirements.
Upvotes: 2