Why can't I inherit from int in C++?

前端 未结 19 2204
不知归路
不知归路 2020-12-02 18:24

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

相关标签:
19条回答
  • 2020-12-02 18:29

    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" ;)

    0 讨论(0)
  • 2020-12-02 18:33

    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)

    0 讨论(0)
  • 2020-12-02 18:33

    No one has 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.

    0 讨论(0)
  • 2020-12-02 18:34

    Please, excuse me for my poor English.

    There is a major difference between C++ correct construction like this:

    struct Length { double l; operator =!?:%+-*/...(); };
    struct Mass { double l; operator =!?:%+-*/...(); };
    

    and the proposed extension

    struct Length : public double ;
    struct Mass   : public double ;
    

    And this difference lies on the keyword this behavior. this is a pointer and using a pointer let few chances to use registers for computations, because in usuals processors registers does not have address. Worst, using pointer make the compiler suspicous about the fact that two pointers may designate the same memory.

    This will put an extraordinary burden on the compiler to optimize trivials ops.

    Another problem is on the number of bugs: reproducing exactly all the behavior of operators is absolutly error prone (for ex making constructor explicit does not forbid all implicits cases). Probability of error while building such an object is quite high. It is not equivalent to have the possibility to do something thru hard work or to have it already done.

    Compiler implementors would introduce type checking code (with maybe some errors, but compiler exactness is much better than client code, because of any bug in compiler generate countless errors cases), but main behavior of operation will remain exactly the same, with as few errors than usual.

    The proposed alternate solution (using structs during debug phase and real floats when optimized ones) is interesting but has drawbacks: it's raise the probability to have bugs only in optimized version. And debugging optimized application is much costly.

    One may implement a good proposal for @Rocketmagnet initial demand for integers types using :

    enum class MyIntA : long {}; 
    auto operator=!?:%+-*/...(MyIntA);
    MyIntA operator "" _A(long);
    

    The bug level will be quite high, like using single member trick, but compiler will treat thoses types exactly like built-in integers (including register capability & optimisation), thanks for inlining.

    But this trick can't be used (sadly) for floating numbers, and the nicest need is obviously real valued dimensions checking. One may not mix up apples and pears: adding length and area is a common error.

    Stroustrup' invocation by @Jerry is irrelevant. Virtuality is meaningful mainly for public inheritance, and the need is here toward private inheritance. Consideration around 'chaotic' C conversion rules (Does C++14 have anything not chaotic?) of basic type are also not useful : the objective is to have no default conversion rules, not to follow standard ones.

    0 讨论(0)
  • 2020-12-02 18:35

    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.

    0 讨论(0)
  • 2020-12-02 18:35

    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.

    0 讨论(0)
提交回复
热议问题