1

我正在做一个小实验,试图在 C++ 中模仿 java 的接口。

我有一个继承自基类“Base”的类“Derived”以及两个接口。我注意到,随着我继承的每个接口,我的 Derived 类的大小都会增加,因为它必须为每个 vptr 添加更多空间。这对我来说似乎非常昂贵,所以我有两个主要问题:

  1. 有没有更好的方法来模仿 C++ 中的 Java 接口?
  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
}
4

3 回答 3

3

关于JAVA:

类超接口对对象大小没有影响。

实现任何 Java 接口只是标记有问题的类,而不会将任何数据添加到其定义中。事实上,JVM 甚至不验证接口实现是否提供了接口所需的所有方法:在当前规范中,这完全是编译器的职责。

从:

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

于 2013-12-21T08:07:45.557 回答
2

是的,派生类型的大小将随着它继承的类的数量而增加。

它增加的确切方式和布局将取决于您正在编译的架构/环境的 ABI。

IA64 ABI是一种相对现代的ABI,许多现代平台似乎都在模仿它。它的文档将使您了解某些环境如何基于各种继承层次结构构建非 POD 类类型。

首先,您的猜测看起来像是在球场上。您需要列出的所有 vptr 和成员。它们在结构中放置的确切顺序,以及该类继承自的所有类之间的对齐约束。(对齐约束可能导致额外的填充。)

所以,对于你的两个问题:

有没有更好的方法来模仿 C++ 中的 Java 接口?

我会说“不”。你现在做的方式在语言中得到了很好的支持,所有的指针规则和多态结构都希望你这样做。

Java 的对象大小会随着每个接口的实现而增加吗?

因为 Java 不给你裸指针,所以可以做其他技巧来减少单个对象的总大小。正如@guarav5430 所指出的,它可以通过跟踪给定对象带外实现的接口集来避免增加单个对象的大小。

因此,您的问题中固有的问题似乎是这些 vptr 等会增加大量存储空间,如果您拥有大量具有如此广泛接口的这些对象,这将是一个问题。根据您正在做的事情,某些设计模式(例如 Flyweight)可能会有所帮助。

于 2013-12-21T07:56:56.833 回答
1

关于

“它必须为每个 vptr [在每个对象中] 添加更多空间”

,它不必。这是内存/速度的权衡。如果再增加一层间接性,每个对象中的单个指针就足够了,它指向此类对象的固定信息,但是虚函数调用可能而且可能会更慢。


关于

“有没有更好的方法来模仿 C++ 中的 Java 接口?”

如前所述,这是没有意义的,因为您不是在模仿 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 部分)。

C++ 选择速度。Java 选择了别的东西。

注:以上上下文为上述上下文。

于 2013-12-21T09:58:15.633 回答