Neil's comment is pretty accurate. Bjarne mentioned considering and rejecting this exact possibility1:
The initializer syntax used to be
illegal for built-in types. To allow
it, I introduced the notion that
built-in types have constructors and
destructors. For example:
int a(1); // pre-2.1 error, now initializes a to 1
I considered extending this notion to
allow derivation from built-in classes
and explicit declaration of built-in
operators for built-in types. However,
I restrained myself.
Allowing
derivation from an int
doesn't
actually give a C++ programmer
anything significantly new compared to
having an int
member. This is
primarily because int
doesn't have
any virtual functions for the derived
class to override. More seriously
though, the C conversion rules are so
chaotic that pretending that int
,
short
, etc., are well-behaved
ordinary classes is not going to work.
They are either C compatible, or they
obey the relatively well-behaved C++
rules for classes, but not both.
As far as the comment the performance justifies not making int a class, it's (at least mostly) false. In Smalltalk all types are classes -- but nearly all implementations of Smalltalk have optimizations so the implementation can be essentially identical to how you'd make a non-class type work. For example, the smallInteger class is represents a 15-bit integer, and the '+' message is hard-coded into the virtual machine, so even though you can derive from smallInteger, it still gives performance similar to a built-in type (though Smalltalk is enough different from C++ that direct performance comparisons are difficult and unlikely to mean much).
Edit: the one bit that's "wasted" in the Smalltalk implementation of smallInteger probably wouldn't be needed in C or C++. Smalltalk is a bit like Java -- when you "define an object" you're really just defining a pointer to an object, and you have to dynamically allocate an object for it to point at. What you manipulate, pass to a function as a parameter, etc., is always just the pointer, not the object itself.
That's not how smallInteger is implemented though -- in its case, they put the integer value directly into what would normally be the pointer. To distinguish between a smallInteger and a pointer, they force all objects to be allocated at even byte boundaries, so the LSB is always clear. A smallInteger always has the LSB set.
Most of this is necessary, however, because Smalltalk is dynamically typed -- it has to be able to deduce the type by looking at the value itself, and smallInteger is basically using that LSB as a type-tag. Given that C++ is statically typed, there's never a need to deduce the type from the value, so you probably wouldn't need to waste that bit.
1 In The Design and Evolution of C++, §15.11.3.