打包类+继承的内存布局

Hem*_*ava 5 c++ g++

考虑到您有两个类,Base和Derived,Derived是从Base公开继承的。

#include <iostream>

struct Base {
  public:
  unsigned char a;
  int b;
  Base() : a('a'), b (2) { };
  unsigned char get_a() {
    return a;
  }
  int get_b() {
    return b;
  }
} __attribute__ ((__packed__)) ;

struct __attribute__ ((__packed__)) Derived : public Base {
  public:
  unsigned char c;
  int d;
  Derived() : c('c'), d(4) { };

  unsigned char get_c() {
    return c;
  }
  int get_d() {
    return d;
  }
};
Run Code Online (Sandbox Code Playgroud)

我正在做一些实验,这些是发现/问题。

首先,您不能在继承链中仅打包一个类。您必须打包链中的所有东西,否则就什么也没有。

其次,打包后,两个类的内存彼此相邻。首先是Base的内存,然后是Derived的内存。例如,Derived的内存布局将是:Base的5个字节,然后Derived的下5个字节。是肯定/正确的吗?

第三,这与我的工作和IMO一个有趣的问题有关。在我的流程中,直到确定的一点,我需要使用基类指针,并且在该特定指针之后,可以通过执行mem_copy或其他操作将所有基类指针转换为派生类指针。当然,我会添加“派生成员”的必要值。我怎样才能做到这一点?

要解决第三个问题,您将建议什么方法?如果没有虚拟,则由于虚拟会向内存增加4/8字节。

Gos*_*low 2

首先,当您谈论编译器扩展时,所有这些都是高度特定于编译器的。

gcc__attribute__ ((__packed__))将对齐设置为 1 并删除填充。这意味着 sizeof(Base) 通常应为 5,而 Derived 按照您的建议添加另外 5 个字节(假设 sizeof(int) == 4)。这就是 pack 在 gcc 和相关编译器(如 clang)中的工作原理。使用不同的编译器,一切都会失败。

至于转换指针,您应该有一个 Derived 的构造函数,它接受一个const Base &参数。编译器应该为此生成正确的 memcpy() 。

总的来说,您应该有充分的理由使用打包,因为对打包结构进行操作会产生效率极低的代码。