+ : ∧[ Int ×Int → Int, Real ×Real → Real ]
void f(int, double); void f(double, int); f(1,2.0);f(int, double);
f(2.0,1);f(double,int);
f(1,1);error: ambiguous
class P; class C; void f(P* p) { cout << "f(P*)"; }(1)
void f(C* c) { cout << "f(C*)"; }(2)
class P { public: virtual void f() { cout << "P::f"; }(3)
}; class C : public P { public: virtual void f() { cout << "C::f"; }(4)
};
P* p = new P;In the example given above, we see that for the functions f (corresponding to (1) and (2)) the choice is determined by the static type of the argument, whereas for the member functions f (corresponding to (3) and (4)) the choice is determined by the dynamic type. We have a dilemma. When we base the choice of functions on the dynamic type of the argument, the function subtype refinement rule is violated. On the other hand, adhering to the domain contravariance property seems to lead to ignoring the potentially useful information captured by the dynamic type of the argument.static and dynamic P*
C* c = new C;static and dynamic C*
P* pc = new C;static P*, dynamic C*
f(p);f(P*)
f(c);f(C*)
f(pc);f(P*)
p->f();P::f
c->f();C::f
pc->f();C::f