L'optimisation de la base vide est excellente. Cependant, il est livré avec la restriction suivante:
L'optimisation de base vide est interdite si l'une des classes de base vide est également le type ou la base du type du premier membre de données non statique, car les deux sous-objets de base du même type doivent avoir des adresses différentes dans la représentation d'objet du type le plus dérivé.
Pour expliquer cette restriction, considérez le code suivant. Le static_assertéchouera. Alors que la modification de Fooou Barde hériter à la place Base2évitera l'erreur:
#include <cstddef>
struct Base  {};
struct Base2 {};
struct Foo : Base {};
struct Bar : Base {
    Foo foo;
};
static_assert(offsetof(Bar,foo)==0,"Error!");Je comprends parfaitement ce comportement. Ce que je ne comprends pas, c'est pourquoi ce comportement particulier existe . Il a évidemment été ajouté pour une raison, car il s'agit d'un ajout explicite et non d'un oubli. Quelle en est la raison?
En particulier, pourquoi les deux sous-objets de base devraient-ils avoir des adresses différentes? Dans ce qui précède, Barest un type et fooest une variable membre de ce type. Je ne vois pas pourquoi la classe de base Barimporte pour la classe de base du type de foo, ou vice-versa.
En effet, je ne sais quoi, je m'attendrais à ce que ce &foosoit la même que l'adresse de l' Barinstance qui la contient - comme cela doit être dans d'autres situations (1) . Après tout, je ne fais rien d'extraordinaire avec l' virtualhéritage, les classes de base sont vides malgré tout, et la compilation avec Base2montre que rien ne casse dans ce cas particulier.
Mais il est clair que ce raisonnement est incorrect d'une manière ou d'une autre, et il existe d'autres situations où cette limitation serait requise.
Disons que les réponses devraient être pour C ++ 11 ou plus récent (j'utilise actuellement C ++ 17).
(1) Remarque: EBO a été mis à niveau en C ++ 11, et en particulier est devenu obligatoire pour StandardLayoutTypes (bien que Bar, ci-dessus, ce ne soit pas a StandardLayoutType).
Base *a = new Bar(); Base *b = a->foo;aveca==b, maisaet cebsont clairement des objets différents (peut-être avec des remplacements de méthode virtuelle différents).