CornedBee: the underpinning of type theory is actually category theory, which is a branch of discrete mathematics. There is very little in mathematics that can't be found to have practical value (although "practical" does not mean the same thing as "understandable to everyone") ....
George: Let's say we have a Base class with a virtual method that returns a pointer to Base, and two Derived classes Derived1 and Derived2 that override that method. So the return value from Base::method() is a Base*, return value from Derived1::method() is a Derived1*, and Derived2::method() returns a Derived2.
If X is the set of classes [Base, Derived1, Derived2] with some ordering so it is considered that Base < Derived1 < Derived2. A simple encoding would be to represent them as distinct integers. Let's say [1,2,3].
Similarly Y denotes the set of return types from the method, namely [Base*, Derived1*, Derived2*] which may be encoded as a set of integers too. Let's say [4,5,6]. This is actually a covariant example (Base->Base*, Derived1->Derived1*, Derived2->Derived2*). The set of pairs (X,Y) are [(1,4), (2,5), (3,6)]. Since the mean of X is 2 and mean of Y is 5, the covariance may be computed as Cov(X,Y) = ((-1)*(-1) + 0*0 + 1*1)/3 = 2/3 (a positive value).
One type of contracovariance (which, as I think CornedBee said earlier, is not possible in C++) would be to reverse the relationship between return value and the containing class. For example, if the return value of Base::method() is Derived2*, Derived1::method returns Derived1, and Derived2::method() returns Base. This would map to a set of pairs (X,Y) which is [(1,6), (2,5), (3,4)] from which Cov(X,Y) = -2/3.
The key in the representation is picking a distinct ordering relationship for types, and ensuring a unique value for each distinct type. There is also a reliance on invariance relationships. For example, in the above, the relationship Base < Derived1 < Derived2 invariably implies the relationship Base* < Derived1* < Derived2*