Я делаю небольшой эксперимент, чтобы попытаться имитировать интерфейсы Java в C ++.
У меня есть класс «Производный», наследующий от базового класса «Базовый», а также два интерфейса. Я замечаю, что с каждым интерфейсом, от которого я наследую, размер моего класса Derived увеличивается, потому что он должен добавить больше места для каждого vptr. Это кажется мне очень дорогим, поэтому у меня есть два основных вопроса:
Вот код, который я использую:
#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
}
Да, размер производного типа будет увеличиваться с увеличением количества классов, от которых он наследуется.
Точный способ его увеличения и макета будет зависеть от ABI для архитектуры / среды, для которой вы компилируете.
IA64 ABI является относительно современным ABI, который, похоже, имитирует ряд современных платформ. Документация к нему даст вам представление о том, как в некоторых средах создается тип класса, отличного от POD, на основе различных иерархий наследования.
На первый взгляд, ваше предположение выглядит так, как будто оно находится на стадионе. Вам нужны все vptrs и участники, которых вы перечислили. Точный порядок их размещения в структуре имеет значение, наряду с ограничениями выравнивания среди всех классов, от которых этот класс наследует. (Ограничения выравнивания могут привести к дополнительному заполнению.)
Итак, на ваши два вопроса:
Есть ли лучший способ имитировать интерфейсы Java в C ++?
Я бы сказал «нет». То, как вы делаете это прямо сейчас, хорошо поддерживается в языке, и все правила указателей и конструкции полиморфизма ожидают, что вы сделаете это таким образом.
Увеличивается ли размер объекта Java с каждым реализованным интерфейсом?
Поскольку Java не дает вам простых указателей, можно выполнять другие приемы, чтобы уменьшить общий размер отдельного объекта. Как отметил @ guarav5430, он может избежать увеличения размера отдельных объектов, отслеживая набор интерфейсов, которые данный объект реализует вне диапазона.
Похоже, в вашем вопросе заложено беспокойство о том, что эти vptr и т. Д. Увеличат объем хранилища, что может быть проблемой, если у вас очень большое количество этих объектов с такими широкими интерфейсами. В зависимости от того, что вы делаете, могут помочь определенные шаблоны дизайна, такие как Flyweight.
в отношении JAVA:
Суперинтерфейсы класса не влияют на размер объекта.
Реализация любого интерфейса Java просто помечает рассматриваемый класс и
не добавляет никаких данных к своему определению. На самом деле, JVM не
даже проверить, что реализация интерфейса предоставляет все методы
требуется интерфейсом: это строго компилятор
ответственность в текущих спецификациях.
от:
http://www.javaworld.com/article/2077408/core-java/sizeof-for-java.html
относительно
«Он должен добавить больше места [в каждом объекте] для каждого 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 выбирает что-то еще.
Примечание: контекст вышеупомянутого является контекстом вышеупомянутого.