2017-01-16 5 views
9

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

struct Empty { 
    /*some methods here*/ 
}; 

и производный класс

struct Derived: Empty { 
    int a; 
    int b; 
    char c; 
    .... 
}__attribute__((packed));` 

Объекты пустого класса имеют размер = 1. Слейте часть производного класса обычно имеет размер 0. Насколько я понимаю, компилятор видит, что базовый пустой класс не имеет данных, поэтому он может оптимизировать размер пустого, если он «внутри» Производится, но это не обязательно для стандартного.

Так что вопрос:

Могу ли я каким-то образом определить во время компиляции, что Empty часть производного класса не реально занимают память.

Я понимаю, что я могу проверить, например, sizeof(Derived) = sizeof(a) + sizeof(b) ... Но это слишком много, и есть несколько классов, таких как Derived. Есть ли более элегантное решение?

+0

Почему вы хотите это знать? Обратите внимание, что член или базовый класс может занимать память без добавления к размеру производного класса (используя пробел, потерянный для заполнения). Также обратите внимание, что 'sizeof' в структуре может быть меньше или больше суммы' sizeof' его членов и баз. – skyking

+0

Я собираюсь использовать эти классы Derived для представления некоторых сетевых данных. Таким образом, все такие производные классы будут иметь упакованный атрибут. Также я собираюсь унаследовать от некоторого класса шаблона для реализации Curiously Recurring Template Pattern. Так что все производные классы будут иметь некоторую общую функциональность. Однако я не хочу, чтобы это наследование влияло на макет классов Derived. –

ответ

11

Вы можете использовать std::is_empty, чтобы убедиться, что класс вы унаследовав от нулевой величины:

static_assert(std::is_empty<Empty>{}); 

Если, empty base optimization является guaranteed to take place for standard-layout classes.


Я понимаю, что я могу сделать проверку, как sizeof(Derived) = sizeof(a) + sizeof(b) ... Но это слишком многословным. Есть ли более элегантное решение?

Это не работает должным образом, потому что вам необходимо учитывать отступы и возможные атрибуты, такие как packed.

+0

Спасибо. Не знал, что эта оптимизация гарантирована. –

+0

Стандарт не гарантирует эту оптимизацию. Это довольно распространено на практике, хотя с реальными компиляторами. – Peter

+1

@Peter: [гарантируется для * стандартных макетов * классов] (http://stackoverflow.com/questions/10788823/is-the-empty-base-class-optimization-now-a-mandatory-optimization-at -least-за). Я уточню свой ответ. –

3

Вы можете использовать более "старый" (перед тем C++ 11) макро - offsetof:

struct Empty {}; 
struct NonEmpty { 
    int a; 
}; 
struct Derived1: Empty { 
    int a; 
    int b; 
    char c; 
}; 
struct Derived2: NonEmpty { 
    int a; 
    int b; 
    char c; 
}; 
static_assert(offsetof(Derived1,a) == 0,""); 
static_assert(offsetof(Derived2,a) != 0,""); 

Вы можете использовать этот макрос, чтобы проверить порядок ваших переменных-членов тоже:

static_assert(offsetof(Derived,a) < offsetof(Derived,b),""); 
static_assert(offsetof(Derived,b) < offsetof(Derived,c),""); 

Но не забывайте - offsetof имеет те же ограничения:

Если тип не является стандартный тип макета, поведение не определено. Если элемент является статическим членом или функцией-членом, поведение не определено.

Смежные вопросы