views:

1266

answers:

17

I'd love to be able to do this:

class myInt : public int
{

};

Why can't I ?

Why would I want to? Stronger typing. For example, I could define two classes intA and intB, which let me do intA+intA or intB+intB, but not intA+intB.

"Ints aren't classes" so?

"Ints don't have any member data" Yes they do, they have 32 bits, or whatever.

"Ints don't have any member functions." Well, they have a whole bunch of operators like + and -.

+5  A: 

In C++ the built-in types are not classes.

Trent
+11  A: 

Because int is a native type and not a class

Edit: moving my comments into my answer.

It comes from the C heritage and what, exactly, primitives represent. A primitive in c++ is just a collection of bytes that have little meaning except to the compiler. A class, on the other hand, has a function table, and once you start going down the inheritance and virtual inheritance path, then you have a vtable. None of that is present in a primitive, and by making it present you would a) break a lot of c code that assumes an int is 8 bytes only and b) make programs take up a lot more memory.

Think about it another way. int/float/char don't have any data members or methods. Think of the primitives as quarks - they're the building blocks that you can't subdivide, you use them to make bigger things (apologies if my analogy is a little off, I don't know enough particle physics)

Mason
That's not an answer, just a restatement of the fact.
Rocketmagnet
@Rocketmagnet, that does not preclude it from being an answer. Your original question asked why it could not be done. You may not have know it was because `int` is not a class; in some languages `int` *is* a class.
Trent
OK, *why* is int not a class ? To me it makes sense to inherit from an int. It would be an object which behaves just like an int.
Rocketmagnet
If it would behave just like an `int`, why would you re-invent int? :]
GMan
It was a design decision when C++ was created that the builtin types would not be classes. Think about it another way. int/float/char don't have any data members or methods. Think of the primitives as quarks - they're the building blocks that you can't subdivide, you use them to make bigger things (apologies if my analogy is a little off, I don't know enough particle physics)
Mason
@Rocketmagnet, most of us will never know why our 'pet features' of any language are not implemented or not implemented the way we think they *should* be. C++ was designed by committee and this is what they decided on.
Trent
@GMan: I think you meant to say "Why would you re-invent int?"
snicker
@snicker: Fix'd.
GMan
@GMan: So punny. Praise The Dood for comment editing abilities. Also +1 for this answer because it is the correct one.
snicker
@Mason: It as also a design decision when Java was created, and the Java designers were going heavily into object orientation. They did provide wrapper classes, but somebody could write a wrapper template in C++.
David Thornley
I don't see anything about "function tables" being part of a class in the standard, Mason. Classes have member functions, but they don't contribute anything to the size of an object.
Rob Kennedy
@Trent The core of C++, still clearly visible today, was not designed by a committee - it was designed (and implemented) principally by one man. Almost all the features in the current C++ standard were present in Cfront 3.0, which well predates it.
anon
@Rob Virtual functions must be implemented somehow, and that implementation must add to the size of an instance. And if you don't have virtual functions, why have inheritance?
anon
@Neil, if inheritance is pointless without virtual functions, then why would C++ be designed to allow inheritance without virtual functions?
Rob Kennedy
@Rob Because it was designed that way. Not every design decision is a good one, but I can't imagine using inheritance without virtual functions - certainly, I've never done so.
anon
@Mason: So we know you're not a string theorist, then. :)
GMan
@Neil, good point about Bjarne not being a committee - I guess we know exactly who to blame then.
Trent
That's begging the question, @Neil. Every decision has a reason. I can think of a few for why this one *might* have been made. 1. Stroustrup or the committee knew that inheritance without virtuals was useless, but didn't bother formalizing a restriction in the standard — users would figure it out for themselves eventually anyway. 2. There *are* reasons for wanting inheritance without virtuals, so it was decided to allow it. 3. It wasn't a decision at all; the issue simply never occurred to anyone at the time. 4. Someone flipped a coin.
Rob Kennedy
@Rob: I'd go for #2.
sbi
@Rob: If you read *Design and Evolution*, you will find that Stroustrup made design decisions that looked good at the moment that he later regretted (I think protected inheritance is the best example). However, Stroustrup wanted to leave options open to the programmer, and was loath to forbid anything without good reason.
David Thornley
Rob Kennedy
@Rob: I'm commenting on your reasons: you seem to have left out "It looked like a good idea to Stroustrup at the moment", as well as commenting on #1: Stroustrup didn't like to make things illegal just because he didn't see a good use. The "protected inheritance" thing may be a fault in my memory, but section 13.9 is about protected data members, and that may be what I was remembering badly.
David Thornley
+49  A: 

Int is an ordinal type, not a class. Why would you want to?

If you need to add functionality to "int", consider building an aggregate class which has an integer field, and methods that expose whatever additional capabilities that you require.

Update

@OP "Ints aren't classes" so?

Inheritance, polymorphism and encapsulation are keystones of object oriented design. None of these things apply to ordinal types. You can't inherit from an int because it's just a bunch of bytes and has no code.

Ints, chars, and other ordinal types do not have method tables, so there's no way to add methods or override them, which is really the heart of inheritance.

David Lively
+1 for proposing an alternate solution.
AJ
If I want *all* the methods, it's becomes a massive and error prone class.
Rocketmagnet
@Rocketmagnet, I don't think anyone is arguing the merits of a language allowing you to extend the primitive types (many languages do). However, it is just not possible in C++. The best solution for you, in C++, is to build an aggregate class which has an integer member as suggested by this answer.
Trent
All **what** methods? Int doesn't have any.
David Lively
All I'd like to know is *why*. Is there some fundamental reason this could not have been done within the design constraints of C++, or did they forget?
Rocketmagnet
@David: Sorry, I meant operators.
Rocketmagnet
Why did someone design the Honda Aztek to look so stupid? It was a design decision. That is the only reason.
snicker
@Rocketmagnet - It comes from the C heritage and what, exactly, primitives represent. A primitive in c++ is just a collection of bytes that have little meaning except to the compiler. A class, on the other hand, has a function table, and once you start going down the inheritance and virtual inheritance path, then you have a vtable. None of that is present in a primitive, and by making it present you would a) break a lot of c code that assumes an int is 8 bytes and b) make programs take up a lot more memory.
Mason
Mason, making it legal to declare subtypes of int doesn't require adding any storage space to int. It particularly doesn't require adding virtual functions to int. If I have an int subclass that has *added* virtual functions, and I assign it to an ordinary int variable, then I have a slicing problem, but that's not unique to this situation.
Rob Kennedy
@Rob If I inherit from int it had better have a virtual destructor.
anon
@Rob, to work properly with virtual functions int would have to have a vtable. if int didn't have any virtual functions, then there would be no benefit from inheriting from it.
SoapBox
@snicker this is quite OT, but the Aztec is by Pontiac, not Honda.
Alex JL
OK, @Soapbox, I'll pose the same question to you as I did to Neil in the comments to Mason's answer. If there's no benefit to inheriting from something without virtual functions, then why was C++ designed to allow that at all? C++ allows allows descending from class types that have no virtual functions, so int's lack of virtual functions cannot be the reason that C++ forbids descending from it.
Rob Kennedy
@snicker The Aztek is a Pontiac. If it was a Honda it would have been very boring and sold a LOT, all of which would still be on the road getting great gas mileage, yet cost a little more than you would expect. And they wouldn't be nearly as ugly.
David Lively
About the Honda; that is a bad analogy. Q: Why does the Honda Aztek have 4 wheels? bad A: Because cars have 4 wheels. good A: Three wheels have been tried, and it's unstable.
Rocketmagnet
@Rob: Other classes do have methods (even if they aren't virtual) which you could benefit from including in a derived class, including some possibly protected ones which then, of course, you could only get by inheriting from it. Also there's obvious benefit to passing around pointers to base classes so that other libraries can use the original base's methods (virtual or not). Since int has no methods at all, these arguments don't apply. You can get basically all of the functionality you want with operator int().
SoapBox
+2  A: 

What does it mean to inherit from an int?

"int" has no member functions; it has no member data, it's a 32 (or 64) bit representation in memory. It doesn't have it's own vtable. All what it "has" (it doesn't really even own them) are some operators like +-/* that are really more global functions than member functions.

anon
int has a bunch of operators. int has member data consisting of 32 or 64 bits.
Rocketmagnet
No, `int` *is* member data.
GMan
@Rocketmagnet: The bits of an int are not members of an int. Twisting words does not alter reality.
Chuck
What difference does that make, @Chuck? An int holds data. A descendant of an int could hold that data just as easily, no? Why does it need to be called *member* data?
Rob Kennedy
@Rob Kennedy: What difference does it make? It makes all the difference. Sure, a "descendent" of an int could be represented by the same bit pattern — in fact, that's all it could do, because an int does not have members. A descendent that can't be any different from its parent is no different from a typedef.
Chuck
Just because the base type doesn't "have members" doesn't mean a descendant couldn't *add* members.
Rob Kennedy
Oh, and Int doesn't "have" operators. The fundamental operators that are part of the language grammar support int, and char, and other ordinal types, but these are part of the language, not methods of a class. At some point, operators have to be resolved to atomic operations. Otherwise, the whole language would eat its own tail and the world would implode into a silly paradox.
David Lively
@GMan, Chuck, David: This is all true and right, but it doesn't answer the question "why is it that way". Those were deliberate design decisions. Stating the outcome of these decisions doesn't explain why they were made.
sbi
@sbi: From my point of view, there's far too many questions about "why is it that way" that seem to assume that a language design emerges full-blown and logically consistent from somewhere, or alternately assume that the language was designed to annoy them by leaving off some favorite feature. There are simply no good answers for many of these questions, aside from "It looked like a good idea to Ritchie/Stroustrup/Gosling/whoever at the time" or "We needed to maintain some compatibility with X".
David Thornley
@David: I don't see Rocketmagnet rejecting answers because they aren't logical. What I see mostly is people restating the facts ("because they're built-ins!") as an attempt to answer why the facts are the way they are. If you think ints aren't inheritable because Stroustrup thought nobody wanted the feature or because he considered it blatantly stupid to even think of it or whatever - go and answer the question that way. But it is a perfectly legal question that ought to get better answers than the "because!" it mostly got in this thread.
sbi
@sbi: And my point is that these questions often have no good answer. A lot of language design decisions are made for no particular reason, and aren't changed later because of compatibility. It happens that Jerry Coffin dug up Stroustrup's reasoning on this case, which is good. Sometimes "because" is the best answer, and it annoys me when people refuse to accept it.
David Thornley
@David: No, that "because" never is a good answer. It's just an attempt to avoid saying "I don't know" or simply shutting up. What if everybody who didn't know the Why refrained from answering "because"? We'd have a perfectly valid question with the usual three or four answers, at least one of which hit the nail right on the head. Instead we have all this noise where everybody tried to hide the fact that they don't know and earn reputation nevertheless.
sbi
@sbi: Sometimes "because" is the only answer. Why does Planck's constant have the value it does? Sometimes the only answer is that it seemed like a good idea at the time. If nobody provided an answer that wasn't certainly good, some questions about language features would go unanswered. Which, I must admit, might be an improvement.
David Thornley
There's quite a difference: Planck's constant was _discovered_, while C++' inheritance mechanism was deliberately designed.
sbi
+4  A: 

What others have said is true... int is a primitive in C++ (much like C#). However, you can achieve what you wanted by just building a class around int:

class MyInt
{
private:
   int mInt;

public:
   explicit MyInt(int in) { mInt = in; }
   // Getters/setters etc
};

You can then inherit from that all you jolly want.

Polaris878
Ok, but you'll want to mark the constructor as `explicit` to prevent automatic conversion.
Steven Sudit
edited... thanks!
Polaris878
But this class behaves nothing like an int.
Rocketmagnet
It's an example, to illustrate a point.
GMan
You have to go to the trouble of adding all the member operators abd typecasting functions to get it to act like an extended `int` type. But once you do, you can then make it a template type that takes `min` and `max` allowable values, and all of the member functions can do range checking.
Loadmaster
Sorry Rocket, you want to "inherit" from int you gotta do the work :)
Polaris878
A: 

If I remember, this was the main - or one of - the main reasons C++ was not considered a true object oriented language. Java people would say: "In Java, EVERYTHING is an object" ;)

Joe
Except that Java also has an int that can't be subclassed, so those people would be wrong :-)
paxdiablo
@Joe: Thankyou, someone who understands the question.
Rocketmagnet
Note that people have different definitions of object orientation, so it would be more accurate to say "some people considered C++ not a true O-O language" or specify who.
David Thornley
+17  A: 

Why would I want to? Stronger typing. For example, I could define two classes intA and intB, which let me do intA+intA or intB+intB, but not intA+intB.

That makes no sense. You can do all that without inheriting from anything. (And on the other hand, I don't see how you could possibly achieve it using inheritance.) For example,

class SpecialInt {
 ...
};
SpecialInt operator+ (const SpecialInt& lhs, const SpecialInt& rhs) {
  ...
}

Fill in the blanks, and you have a type that solves your problem. You can do SpecialInt + SpecialInt or int + int, but SpecialInt + int won't compile, exactly as you wanted.

On the other hand, if we pretended that inheriting from int was legal, and our SpecialInt derived from int, then SpecialInt + int would compile. Inheriting would cause the exact problem you want to avoid. Not inheriting avoids the problem easily.

"Ints don't have any member functions." Well, they have a whole bunch of operators like + and -.

Those aren't member functions though.

jalf
+1 for addressing the real problem (operator overloading)
LiraNuna
A: 

This is related to how the items are stored in memory. An int in C++ is an integral type, as mentioned elsewhere, and is just 32 or 64 bits (a word) in memory. An object, however, is stored differently in memory. It is usually stored on the heap, and it has functionality related to polymorphism.

I don't know how to explain it any better. How would you inherit from the number 4?

Erik A. Brandstadmoen
Objects are usually stored on the heap in C++? Isn't that a bit of an overgeneralization?
Chuck
Also, number 4 isn't a type. It's a value that a variable of type int might hold. Also objects don't necessarily have to be polymorphic (see your STL).
UncleBens
Here are two variables: `int x; struct { int i; } y;` Erik, please describe how `x` and `y` are stored differently in memory.
Rob Kennedy
@UncleBens: There are languages with prototype-based object system, where you can inherit from an instance. This is pretty standard in languages for writing text adventures/interactive fiction, such as Inform and TADS. It's just that C++ doesn't work that way.
David Thornley
I don't want to inherit from the number 4, I want to inherit from int.
Rocketmagnet
@Rob: Structs are also integral (basic) types. They cannot be instantiated, and are not objects.
Erik A. Brandstadmoen
@Chuck: Where objects are stored, was not the main point of my post. And, you CAN store objects on the heap, if I recall correctly (it's been quite a while since I did C++ programming), But, usually you have a reference to your object (on the stack), and the object itself is stored on the heap. The pointer is destroyed when you exit your scope, however, the object lives on if you don't delete it. This could lead to memory leaks.However, my point was, integral types are not stored in the same way as objects, and it doesn't make sense to inherit from them. Then they would have to be object types
Erik A. Brandstadmoen
@Eric, you seem to have no idea what you're talking about. In my previous comment, `y` is an instance of the anonymous struct defined right there. If it had a name (say, `Y`), you could also instantiate it like this: `Y* z = new Y;` The variables `x`, `y`, and now `z`, are all objects. (Check the standard for its definition of *object*; if you think it's "instance of a class," you're wrong.) You *can* store objects on the heap, but saying they're *usually* there is an overstatement. They're frequently on the stack, too. Integral types are stored the same as other types.
Rob Kennedy
@Rob: I won't get into an argument of C++ details, I'm not proficient enough in the language (far from) to do so. However, I think we are getting a bit off track. The initial question was why the author couldn't inherit from an int (which is a basic type). I'll stop arguing this now, as I feel we're getting a bit OT :)
Erik A. Brandstadmoen
+10  A: 

If the OP really wants to understand WHY C++ is the way it is, then he should get a hold of a copy of Stroustup's book "The Design and Evolution of C++". It explains the rationale for this and many other design decisions in the early days of C++.

Stephen C. Steel
Rocketmagnet
+1  A: 

As others I saying, can't be done since int is a primitive type.

I understand the motivation, though, if it is for stronger typing. It has even been proposed for C++0x that a special kind of typedef should be enough for that (but this has been rejected?).

Perhaps something could be achieved, if you provided the base wrapper yourself. E.g something like the following, which hopefully uses curiously recurring templates in a legal manner, and requires only deriving a class and providing a suitable constructor:

template <class Child, class T>
class Wrapper
{
    T n;
public:
    Wrapper(T n = T()): n(n) {}
    T& value() { return n; }
    T value() const { return n; }
    Child operator+= (Wrapper other) { return Child(n += other.n); }
    //... many other operators
};

template <class Child, class T>
Child operator+(Wrapper<Child, T> lhv, Wrapper<Child, T> rhv)
{
    return Wrapper<Child, T>(lhv) += rhv;
}

//Make two different kinds of "int"'s

struct IntA : public Wrapper<IntA, int>
{
    IntA(int n = 0): Wrapper<IntA, int>(n) {}
};

struct IntB : public Wrapper<IntB, int>
{
    IntB(int n = 0): Wrapper<IntB, int>(n) {}
};

#include <iostream>

int main()
{
    IntA a1 = 1, a2 = 2, a3;
    IntB b1 = 1, b2 = 2, b3;
    a3 = a1 + a2;
    b3 = b1 + b2;
    //a1 + b1;  //bingo
    //a1 = b1; //bingo
    a1 += a2;

    std::cout << a1.value() << ' ' << b3.value() << '\n';
}

But if you take the advice that you should just define a new type and overload the operators, you might take a look at Boost.Operators

UncleBens
Thanks UncleBens. This is a useful answer. I think that a combination of Alex Brown's answer with Boost::Operators would be good.
Rocketmagnet
A: 

More general than the fact that "int is primitive" is this: int is a scalar type, while classes are aggregate types. A scalar is an atomic value, while an aggregate is something with members. Inheritance (at least as it exists in C++) only makes sense for an aggregate type, because you can't add members or methods to scalars — by definition, they don't have any members.

Chuck
for some, `class` is syntax to express a type, and subclassing means restricting the domain. like naturals are a subtype of integers, which are a subtype of reals, etc.
just somebody
Guess what? Those "some" are living in la la land. You're talking about how you wish it were, not how it is. I deal in the real world. class is not a generic syntax to express the mathematical concept of type in C++.
Chuck
@Chuck: What you say is all well and good, except that the question wasn't "how is it?" but "why is it that way?" Neither your answer nor your (somewhat rude) comment answers the right question.
sbi
The question was "Why can't I do this?" The answer is "Because `int` is a scalar, and the C++ concept of subtyping is not meaningful for scalars." Integers weren't arbitrarily excluded — it's not possible to apply the concept as it exists to them. That is **why**.
Chuck
@Chuck: No that isn't why. That's just stating the facts without explaining why they are the way they are. There is a very good answer to these questions and, not surprisingly, it also is the accepted answer.
sbi
A: 

Why can't you inherit from int, even though you might want to?

Performance

There's no functional reason why you shouldn't be able (in an arbitrary language) inherit from ordinal types such as int, or char, or char* etc. Some languages such as Java and Objective-C actually provide class/object (boxed) versions of the base type, in order to satisfy this need (as well as to deal with some other unpleasant consequences of ordinal types not being objects):

language     ordinal type boxed type, 
c++          int          ?
java         int          Integer
objective-c  int          NSNumber

But even Java and objective-c preserve their ordinal types for use... why?

The simple reasons are performance and memory consumption. An ordinal type can be typically be constructed, operated upon, and passed by value in just one or two X86 instructions, and only consumes a few bytes at worst. A class typically cannot - it often uses 2x or more as much memory, and manipulating its value may take many hundreds of cycles.

This means programmers who understand this will typically use the ordinal types to implement performance or memory usage sensitive code, and will demand that language developers support the base types.

It should be noted that quite a few languages do not have ordinal types, in particular the dynamic languages such as perl, which relies almost entirely on a variadic type, which is something else altogether, and shares some of the overhead of classes.

Alex Brown
You can easily construct wrapper classes in C++ that adds semantics to primitive types but compiles down to the exact same assembly as using the primitive directly, (or calling a non-member function that operates on the primitive). A language need not go the Java way and provide you an Integer class that behaves differently than the primitive equivialent.
nos
yes, you are right, you can. But they aren't provided out of the box, hence the ? in the table.
Alex Brown
also, if there were provided out of the box, they would have virtual functions and be based upon a base class and have members in addition to their main value. count on it. For example, the Java Int type has a lock in it, as well as the int (and who knows what else?)
Alex Brown
Alex, I disagree. int has no virtual functions, therefore there will be no vtable. If I add no other members, then MyInt is exactly the same size as int, and should compile to identical code. The only difference will be compile time checking of my types.
Rocketmagnet
+25  A: 

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.

Jerry Coffin
Finally, someone comes up with the exact reason. +1
sbi
I don't know the internal representation of integers in Smalltalk, but a 15-bit integer is not useful in a language trying to work with or extend C. It's too small to be a `short`, and I doubt it can be used to make compact bitfields. If the cost of being able to derive from raw integer types is one bit of overhead per integer, it's far too high for a language like C++. It's a valid approach in language design in general, but any language that does that will have compatibility issues with C.
David Thornley
@David Thornley:while it's true that 15 bits is on the small side, keep in mind that smallInteger was defined sometime before 1980. If I were implementing Smalltalk today, I'd probably make it 63 bits, adequate for all integer types except `long long`.
Jerry Coffin
Thanks, this is a good answer!
Rocketmagnet
@Jerry: Do you know if Smalltalk really requires the extra bit? A 63-bit integer is technically legal for `int`, but it's still going to have compatibility problems with C.
David Thornley
+5  A: 

No-ones mentioned that C++ was designed to have (mostly) backwards compatibility with C, so as to ease the upgrade path for C coders hence struct defaulting to all members public etc.

Having int as a base class that you could override would fundamentally complicate that rule no end and make the compiler implementation hellish which if you want existing coders and compiler vendors to support your fledgling language was probably not worth the effort.

zebrabox
I don’t see that as valid. The original int wouldn’t behave any different to the int form which you could inherit. And it’s not like C had a method to check whether a type is expected to be a class.
Debilski
@Debilski BS. If you're using pointer arithmetic to iterate through a malloc'd block of memory, increment by sizeof(int) should be by 2 or 4 bytes ( depending on the bandwidth of your system as defined in limits.h) not by the instance size of an Int, which will certainly be different. Go write a compiler and let us know how it goes.
David Lively
Why would the instance size be different? It doesn’t carry any information apart from the value of an `int`? I don’t need my own compiler to prove that.
Debilski
@David: From the point of view of language design, an `Int` class that has no ability to have virtual functions is very limited as a base class, and therefore arguably not worth having. From the point of view of implementation, a class with virtual functions needs one vtable pointer per instance.
David Thornley
@David: There would be no vtable, because there are no virtual functions. The derived int class would be the same size as the original int.
Rocketmagnet
+3  A: 

Well, you don’t really need to inherit anything which hasn’t got any virtual member functions. So even if int were a class, there would not be a plus over composition.

So to say, virtual inheritance is the only real reason you’d need inheritance for anyway; everything else is just saving you masses of typing time. And I don’t think an int class/type with virtual members would be the smartest thing to imagine in the C++ world. At least not for you every day int.

Debilski
+2  A: 

strong typing of ints (and floats etc) in c++

Scott Meyer (Effective c++ has a very effective and powerful solution to your problem of doing strong typing of base types in c++, and it works like this:

Strong typing is a problem that can be addressed and evaluated at compile time, which means you can use the ordinals (weak typing) for multiple types at run-time in deployed apps, and use a special compile phase to iron out inappropriate combinations of types at compile time.

#ifdef STRONG_TYPE_COMPILE
typedef time Time
typedef distance Distance
typedef velocity Velocity
#else
typedef time float
typedef distance float
typedef velocity float
#endif

You then define your Time, Mass, Distance to be classes with all (and only) the appropriate operators overloaded to the appropriate operations. In pseudo-code:

class Time {
  public: 
  float value;
  Time operator +(Time b) {self.value + b.value;}
  Time operator -(Time b) {self.value - b.value;}
  // don't define Time*Time, Time/Time etc.
  Time operator *(float b) {self.value * b;}
  Time operator /(float b) {self.value / b;}
}

class Distance {
  public:
  float value;
  Distance operator +(Distance b) {self.value + b.value;}
  // also -, but not * or /
  Velocity operator /(Time b) {Velocity( self.value / b.value )}
}

class Velocity {
  public:
  float value;
  // appropriate operators
  Velocity(float a) : value(a) {}
}

Once this is done, your compiler will tell you any places you have violated the rules encoded in the above classes.

I'll let you work out the rest of the details yourself, or buy the book.

Alex Brown
Thanks Alex. This is roughly what I'm after. I just wondered if it would be possible to do this without having to re-specify all the operators every time.
Rocketmagnet
A: 

You can get what you want with strong typedefs. See BOOST_STRONG_TYPEDEF

Vicente Botet Escriba