Why Can't I Inherit from Int in C++

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

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).

The one bit that's "wasted" in the Smalltalk implementation of smallInteger (the reason it only represents 15 bits instead of 16) 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 on a type-tag.


1. In The Design and Evolution of C++, §15.11.3.

why can't I access this method via inheritance?

Because Bar::stuff hides Foo::stuff (only the name matters when overload resolution is performed, parameters are ignored).

You can :

  • Bring it into sope with a using declaration
  • Or alternatively, explicitly qualify the call e.g. b.Foo::stuff(3);.

Note :

  • main() must return an int.

#include <iostream>

class Foo
{
public:
int a;
void stuff(int a){ std::cout << a << std::endl; }
};

class Bar : public Foo
{
public:
using Foo::stuff;
protected:
void stuff() { std::cout << "hello world"; }
};

int main()
{
Bar b;
b.stuff(3);
}

Or :

int main()
{
Bar b;
b.Foo::stuff(3);
}

Not Inherit from Base Class C++

I'm not sure what answer the questioner was expecting, but here's some possible solutions:

Make 'A' a pointer:

//Only takes 4 or 8 bytes (32 bit vs 64 bit code) for 'A', regardless of 'A's actual size, but must point to an 'A' located elsewhere in memory with the full size.
class B
{
A *a; //Only 4 bytes.
int b;
};

Make 'A' static:

//Doesn't assume any of 'A's size, but all instances of 'B' shares a single instance of 'A'.
class B
{
static A a;

int b;
};

Pass 'A' into the functions of 'B':

//Pass in the reference to 'a' when needed, so multiple 'B's can share the same 'a' explicitly when desired.
class B
{
void q(A &a) { this->b + a.a; return a.g(); }
};

Make 'A' and 'B' not have virtual tables (probably the interviewer's point)

//By not having virtual functions, you save the (really small) cost of 4 bytes (8 bytes on 64 bit machines)
class A
{
public:
int f() { }; //Not virtual
int a;
}

class B : public A
{
public:
int g() { }; //Not virtual
int b;
}

It still costs you the size of A::a, and, unless you re-use 'a' in B instead of having B::b, you can't avoid those 4 bytes. And re-using one variable to mean something else entirely is a possible sign of really bad programming habits.

Unionize A'a and B's variables and put the functions in a single class

class AB //Only 4 bytes total
{
public:
union
{
int a;
int b;
};

void f();
void g();
};

The bad idea about this is, you'll have to keep track of whether you should access 'a' or 'b', because both of them occupy the same 4 bytes of memory, and they can't both be using it at the same time.

Another bad thing about this is that it is a sign that the class has too much responsibility. Is it an A or a B? If it's both, the all important question should be, "Why is it both?". It should have a single-responsibility, not be a monolith of mixed purposes.

Make 'A' a template, and inherit from A<B>:

template<typename TypeB>
class A
{
int a;
};

//Saves the cost of the virtual table... not that that really matters.
class B : public A<B>
{
int b;
};

This last one is called the 'curiously recurring template pattern' (CRTP)
The idea is that the inherited 'A<B>' can call access variables and functions from 'B' (if you pass B's 'this' pointer into A's constructor), and 'B' can access variables and functions directly from 'A<B>'.

You're inheriting from a compile-time generated version of the template 'A', that is generated for 'B'.

Why can't the class inherit the member types of its parents?

The member U is inherited like any other member would be, irrespective of which classes are templated, but it is not found by unqualified name lookup according to C++17 [temp.dep]/3:

In the definition of a class or class template, the scope of a dependent base class (17.6.2.1) is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

Here, A<T> is a dependent base class since it depends on the template parameter T of the class template D.

To force the compiler to look up U in the base class, you have to use qualified name lookup. You can do it like this:

void f(typename A<T>::U);

Another way of expressing it, if the template arguments to the base class are complicated, is:

void f(typename D::A::U);

If you are going to be writing this out multiple times then you could also redeclare the type in D for convenience:

using U = typename A<T>::U;
void f(U);

Note: in the above contexts, typename will become optional in C++20.

VS2008 C++ can't seem to inherit const overloaded method

This error you are receiving will happen in every compiler (including gcc, msvc 2013, etc..)

no matching function for call to ‘Child::doIt(const int&)’ sc.doIt(c_i);

That is the problem. You are overriding the function doIt and only providing one override when the parent class has two. It won't search the parent class since you are overriding it.

You should provide both overrides:

struct Child : public Base
{
virtual void doIt(int& v){cout << "Child NonConst v=" << v << endl;}
virtual void doIt(const int& v) const { Base::doIt(v);}
};

OR you can also do a using statement like so (C++11):

struct Child : public Base
{
virtual void doIt(int& v){cout << "Child NonConst v=" << v << endl;}

using Base::doIt;
};

C++ Why base class/struct constructor can't have more than one argument to be implicitly callable from derived?

The "magic" is that you're accidentally using aggregate initialization. In C++20 (and not before), you can invoke aggregate initialization by using parenthesis instead of curly braces, so long as no actual constructor (like the copy/move constructor) would have been invoked. This was done to allow indirect construction of types (emplace, optional's in-place constructor, make_shared/unique, etc) to work on aggregate types.

Your type Derived is an aggregate, as it has no user-provided constructors and one subobject (the base class). So your use of constructor syntax will invoke aggregate initialization, with the first aggregate member being the base class. Which can be constructed from an int (BTW, it's generally bad form to not make constructors from a single parameter explicit unless they're copy/move constructors).

Generally speaking, unless you are intending to create an aggregate (ie: the type is just an arbitrary bundle of values), derived classes ought to have constructors. I can't recall when I've written a derived class that didn't also have at least one constructor. And if it is your intent for the derived class to have the base class constructors, you should explicitly spell that out whenever you want to do that. Constructors are not inherited without explicit say-so.

Thou shalt not inherit from std::vector

Actually, there is nothing wrong with public inheritance of std::vector. If you need this, just do that.

I would suggest doing that only if it is really necessary. Only if you can't do what you want with free functions (e.g. should keep some state).

The problem is that MyVector is a new entity. It means a new C++ developer should know what the hell it is before using it. What's the difference between std::vector and MyVector? Which one is better to use here and there? What if I need to move std::vector to MyVector? May I just use swap() or not?

Do not produce new entities just to make something to look better. These entities (especially, such common) aren't going to live in vacuum. They will live in mixed environment with constantly increased entropy.

Why can you inherit from interfaces in C++

This makes no sense to me. Map is an interface

In Java, it is. In C++, it's not even a class, it is a class template. C++ does not have a concept similar to Java's interfaces, although you can implement something similar with virtual inheritance.

As far as the collection classes are concerned, C++ solved with templates and generic programming what Java solved with interfaces and inheritance.

Instances of C++ map template are fully functioning classes that work similarly to Java's TreeMap. You can inherit them in the same way that you inherit from classes in Java, and because of multiple inheritance, you are not limited to a single class.

Also, I don't understand why you would use a typedef.

You use typedef to give classes meaningful names. In addition to shortening your typing, it makes your program more readable, and gives you additional flexibility at redefining the class behind the typedef later on.

Note: the fact that you can inherit from standard containers does not mean that you should do it. Read answers to this question for more information.



Related Topics



Leave a reply



Submit