2013-12-21 3 views
1

Я делаю небольшой эксперимент, чтобы попытаться имитировать интерфейсы Java на C++.Размер объекта C++ увеличивается по мере добавления дополнительных интерфейсов ... делает ли это Java?

У меня есть класс «Производный», наследующий базовый класс «База», а также два интерфейса. Я замечаю, что с каждым унаследованным интерфейсом размер моего класса Derived увеличивается, потому что он должен добавить больше места для каждого vptr. Мне кажется, это очень дорого, поэтому у меня есть два основных вопроса:

  1. Есть ли лучший способ имитировать интерфейсы Java на C++?
  2. Увеличивает ли размер объекта Java каждый интерфейс?

Вот код, я использую:

#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 
} 

ответ

2

Да, размер производного типа будет увеличиваться с числом классов он наследует от.

Точный способ его увеличения, а макет будет зависеть от ABI для архитектуры/среды, которую вы компилируете.

IA64 ABI - относительно современный ABI, который, похоже, воспроизводит несколько современных платформ. Документация для него даст вам представление о том, как некоторые среды создают тип класса, отличного от POD, на основе различных иерархий наследования.

В первом порядке ваша догадка выглядит так, как будто она находится на футбольном поле. Вам нужны все vptrs и члены, которые вы указали. Точный порядок, в котором они размещены в структуре, зависит от ограничений выравнивания среди всех классов, от которых этот класс наследуется. (Alignment ограничение может привести к дополнительной набивке.)

Таким образом, чтобы ваши два вопроса:

Есть ли лучший способ имитировать интерфейсы в Java в C++?

Я бы сказал «нет». То, как вы делаете это сейчас, хорошо поддерживается в языке, и все правила указателя и конструкции полиморфизма ожидают, что вы сделаете это так.

Увеличивает ли размер объекта Java каждый интерфейс?

Поскольку Java не дает вам голых указателей, вы можете делать другие трюки, чтобы уменьшить общий размер отдельного объекта. Как отметил @ guarav5430, он может избежать увеличения размера отдельных объектов, отслеживая набор интерфейсов, данный объект реализует внеполосные.

В связи с тем, что ваш вопрос, кажется, вызывает беспокойство, что эти vptrs и т. Д. Будут содержать значительное хранилище, что будет проблемой, если у вас есть очень большое количество этих объектов с такими широкими интерфейсами. В зависимости от того, что вы делаете, некоторые шаблоны проектирования, такие как Flyweight, могут помочь.

+0

Обратите внимание, что OP ** не ** имитирует интерфейсы Java. –

3

относительно JAVA:

Класс суперинтерфейсах не оказывают никакого влияния на размер объекта.

Внедрение любого интерфейса Java просто отмечает класс, о котором идет речь, и не добавляет никаких данных в его определение. На самом деле JVM не даже подтверждает, что реализация интерфейса предоставляет все методы , необходимые для интерфейса: это строго ответственность компилятора в текущих спецификациях.

от:

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

1

Что касается

“ он должен добавить больше пространства [в каждом объекте] для каждого vptr ”

Нет, это Безразлично 't есть. Это компромисс между памятью и скоростью. С еще одним уровнем косвенности достаточно одного указателя в каждом объекте, указывая на фиксированную информацию для объектов этого класса, но тогда вызовы виртуальных функций могли и, вероятно, были бы медленнее.


Что касается

“ есть лучший способ, чтобы имитировать интерфейсы в Java в C++? ”

Как сказано это не имеет смысла, потому что вы не имитируя интерфейсы Java.

Основная функциональность интерфейса Java заключается в том, что вы можете наследовать реализацию из базового класса. Для этого в C++ вы можете использовать виртуальное наследование . Таким образом:

#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 
} 

Что касается

“ ли в Java размера объекта идти с каждым реализованным интерфейсом? ”

Nope (основано на gaurav5430's answer, about the Java part only).

C++ выбирает скорость. Java выбирает что-то другое.

Примечание: в контексте вышеизложенного приведен контекст вышеизложенного.

+1

Java (более конкретно, HotSpot) выбирает * еще большую скорость *, чем C++: компилятор JIT будет агрессивно реализовывать сайт вызова как мономорфный, когда данные профилирования времени выполнения указывают, что на этом конкретном сайте отправляется только один тип. Мономорфное место вызова включает в себя * нулевые * уровни косвенности и дополнительно открывает дверь для оптимистичной вставки, удаляя даже вызов самого метода. Существуют дополнительные методы для отправки на небольшое количество типов. –

+0

@MarkoTopolnik: Ваш комментарий кажется несущественным или просто вводит в заблуждение относительно указателей vtable в объектах. Насколько я понимаю, вы реагируете на замечание о выборе Java для этого компромисса как негативного для Java и хотите подчеркнуть, что в некоторых других аспектах Java может быть довольно быстрым. Однако, независимо от того, насколько важно, что это может показаться, это очень не по теме, не связано с вопросом ОП, и поэтому это не место ** для таких наблюдений или впечатлений. –

+0

Это как (ir) актуально как ваше заключительное замечание, что явно подразумевает, что, в отличие от C++, Java не выбирает скорость. Выбор индивидуальной детали оформления (в центре таблицы vtable) не может вернуть никаких претензий на одеяло, таких как таковые. Ну, в некотором смысле вы правы: это «что-то другое», на которое выбирает Java, - это * больше скорости *. –