Size of C++ object increases as I add more interfaces... does Java do this?

665 views Asked by At

I'm doing a little experiment to try to mimic java's interfaces in C++.

I have a class "Derived" inheriting from base class "Base" and also two interfaces. I notice that with each interface I inherit from, the size of my Derived class goes up, because it has to add more space for each vptr. This seems very expensive to me, so I have two main questions:

  1. Is there a better way to mimic Java's interfaces in C++?
  2. Does Java's object size go up with every interface implemented?

Here's the code I'm using:

#include <iostream>

class Base {
public:
    int derp;
    virtual int getHerp() = 0;
    virtual ~Base() { }
};

class Interface1 {
public:
    virtual int getFlippy() = 0;
    virtual ~Interface1() { }
};

class Interface2 {
public:
    virtual int getSpiky() = 0;
    virtual ~Interface2() { }
};

class Derived : public Base, public Interface1, public Interface2 {
public:
    int herp;
    virtual int getHerp() { return herp; }
    virtual int getFlippy() { return 6; }
    virtual int getSpiky() { return 7; }
};

int main() {
    Derived d;
    std::cout << sizeof(d) << std::endl;
    // prints 40. presumably, Derived/Base vptr + derp + Interface1vptr + Interface2 vptr + herp
}
3

There are 3 answers

1
Joe Z On BEST ANSWER

Yes, the size of the derived type will increase with the number of classes it inherits from.

The exact way it increases and the layout will depend on the ABI for the architecture / environment you're compiling for.

The IA64 ABI is a relatively modern ABI that a number of modern platforms seem to mimic. The documentation for it will give you an idea of how some environments build up a non-POD class type based on various inheritance hierarchies.

To a first order, your guess looks like it's in the ballpark. You need all the vptrs and members you listed. The exact order in which they're placed in the structure matter, along with the alignment constraints among all classes this class inherits from. (Alignment constraints can lead to additional padding.)

So, to your two questions:

Is there a better way to mimic Java's interfaces in C++?

I would say "no." The way you're doing it right now is well supported within the language, and all of the pointer rules and polymorphism constructs expect you to do it this way.

Does Java's object size go up with every interface implemented?

Because Java doesn't give you bare pointers, can do other tricks to reduce the total size of an individual object. As @guarav5430 noted, it can avoid increasing the size of individual objects by tracking the set of interfaces a given object implements out-of-band.

So inherent in your question seems to be a concern that these vptrs, etc. will add up to significant storage, which would be a concern if you have a very large number of these objects with such broad interfaces. Depending on what you're doing, certain design patterns such as Flyweight might help.

0
gaurav5430 On

regarding JAVA:

Class superinterfaces have no impact on the object size.

Implementing any Java interface merely marks the class in question and does not add any data to its definition. In fact, the JVM does not even validate that an interface implementation provides all methods required by the interface: this is strictly the compiler's responsibility in the current specifications.

from:

http://www.javaworld.com/article/2077408/core-java/sizeof-for-java.html

6
Cheers and hth. - Alf On

Regarding

“ it has to add more space [in each object] for each vptr”

No, it doesn't have to. This is a memory/speed trade-off. With one more level of indirection a single pointer in each object would suffice, pointing to the fixed information for objects of this class, but then virtual function calls could and probably would be slower.


Regarding

“Is there a better way to mimic Java's interfaces in C++?”

As stated this is meaningless, because you're not mimicking Java's interfaces.

The main functionality of a Java interface is that you can inherit in an implementation from a base class. To do that in C++ you can use virtual inheritance. Thus:

#include <iostream>

class Base {
public:
    virtual int getHerp() = 0;
    virtual ~Base() { }
};

class Interface1 {
public:
    virtual int getFlippy() = 0;
    virtual ~Interface1() { }
};

class Interface2 {
public:
    virtual int getSpiky() = 0;
    virtual ~Interface2() { }
};

class Flippy_impl
    : public virtual Interface1
{
public:
    virtual int getFlippy() { return 6; }
};

class Derived
    : public Base
    , public virtual Interface1, public virtual Interface2
    , public Flippy_impl
{
public:
    virtual int getHerp() { return 0; }
    virtual int getSpiky() { return 7; }
};

int main() {
    Derived d;
    std::cout << sizeof(d) << std::endl;
    // prints 12. presumably, Derived/Base vptr + Interface1vptr + Interface2 vptr
}

Regarding

“Does Java's object size go up with every interface implemented?”

Nope (based on gaurav5430's answer, about the Java part only).

C++ opts for speed. Java opts for something else.

Note: the context of the above is the context of the above.