typeof returns the type of the internal representation of C and is not used to send the method. So strictly speaking, you cannot think of types as "superclasses."
Instead of base classes (numerical, symbolic, list, function, etc.) that approximately correspond to the names, typeof returned, but not always (for example, the double type has a numerical class, the special function and the class closure, and the data.frame class has a list of types !).
With S3 and S4 systems, you can create non-trivial classes using base classes (but not necessarily one of them !!) Example: setClass("foo", list(a="numeric",b="character") not extends to none of the base classes ).
For objects from these base classes, is.object returns FALSE . As its documentation says, this function provides a very quick way to check if an object has a custom class S3 or S4 (i.e. not one of the base classes).
After casting x as "fake", your object does not formally belong to the "numerical" class:
is(x, "numeric")
but it is interpreted as a basic "numerical" object:
is.numeric(x)
And that's why + works here. So internally, since @Richie already said that the default method interprets x as a numeric base class.
This conceptual mess is due to an informal relationship with the S3 classes. Use S4 instead.
correspondence between typeof (.) and base class (.):
typeof(.) class(.) NULL "NULL" "NULL" 1 "double" "numeric" 1:1 "integer" "integer" 1i "complex" "complex" list(1) "list" "list" data.frame(x=1) "list" "data.frame" pairlist(pi) "pairlist" "pairlist" c "special" "function" lm "closure" "function" formals(lm)[[1]] "symbol" "name" formals(lm)[[2]] "symbol" "name" y~x "language" "formula" expression((1))[[1]] "language" "(" (y~x)[[1]] "symbol" "name" expression(x <- pi)[[1]][[1]] "symbol" "name"