I would like to create a nice interface on C++ on which each implementation needs to have the addition defined, on itself.
I would like to do something like this :
class A{
...
virtual A& operator+(const A& other) =0;
...
}
// this is my interface or abstract class.
class B : A{
...
B& operator+(const B& other);
...
}
// this is the kind of implementation i would like. a B element can be added by another B element only ! At least this the constraint I am aiming at.
as c++ does not accept contravariance, my function B& operator+(const B& other)
does not implement virtual A& operator+(const A& other)
. Is there any tricky (but a little bit clean...) way to do that?
Covariance and contravariance are terms that refer to the ability to use a more derived type (more specific) or a less derived type (less specific) than originally specified. Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types.
An abstract class cannot be inherited by structures. It can contain constructors or destructors.
Abstract classes have the following features: An abstract class cannot be instantiated. An abstract class may contain abstract methods and accessors. It is not possible to modify an abstract class with the sealed modifier because the two modifiers have opposite meanings.
In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.
template<class Y>
class A
{
virtual Y& operator+=(const Y& other) = 0;
};
class B : A<B>
{
// must implement B& operator+=(const B& other) else B is abstract
};
is one way. This idiom is common when implementing policies. See http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
What you are trying to do is not possible in any language, because it does not make sense.
It is true that methods are contravariant in argument types in some languages, but that means that method is an overload if it accepts supertype. I.e. operator+(const A&)
would be overload for operator+(const B&)
. But not the other way around. Because when you have two A instances (let's call them x
and y
) and write x + y
, the method will be called and the compiler can't know whether both will be of the same subtype as that information will only be available at runtime. So at runtime is the only time you can check it.
So:
+
in the template that will be using it (it must be a template if it's not polymorphic) and the compiler will bitch when it's not defined. You may write a concept check class to find out early and avoid errors with too deep template expansion stack.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With