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

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

У меня есть класс «Производный», наследующий от базового класса «Базовый», а также два интерфейса. Я замечаю, что с каждым интерфейсом, от которого я наследую, размер моего класса 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
}

1

Решение

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

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

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

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

Итак, на ваши два вопроса:

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

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

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

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

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

2

Другие решения

в отношении JAVA:

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

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

от:

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

3

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

«Он должен добавить больше места [в каждом объекте] для каждого vptr»

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


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

«Есть ли лучший способ имитировать интерфейсы 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 с каждым реализованным интерфейсом?»

Нет (на основе ответ gaurav5430, только о части Java).

С ++ выбирает скорость. Java выбирает что-то еще.

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

1
По вопросам рекламы [email protected]