OVH Cloud OVH Cloud

héritage privé + héritage virtuel

3 réponses
Avatar
Frédéric Gourul
Bonjour à tous.

En faisant quelques tests pour règler un problème d'appel de constructeur
avec un héritage virtuel, je me suis appercu que l'héritage privé de la
classe B gênait mon compilateur lors de la construction par copie de la
classe D. Cela m'oblige à déclarer explicitement le constructeur de copie
alors que celui par défaut me convenait parfaitement.

J'ai testé le même code avec gcc qui lui ne dit rien...
Je testerai le même code avec VC7 ce soir pour voir ce qu'il en dit.

class A
{
public:
int m;
A() :m(0) {cout << "A default constructor" << endl;}
A(const A& a) :m(a.m) {cout << "A copy constructor" << endl;}
void operator=(const A& a) {m = a.m; cout << "A copy operator" << endl;}
};

class B : public virtual A
{
public:
B() {cout << "B default constructor" << endl;}
B(const B& a) :A(a) {cout << "B copy constructor" << endl;}
void operator=(const B& a) {A::operator=(a); cout << "B copy operator" <<
endl;}
};

class C : private B
{
private:
using B::m;

public:
C() {cout << "C default constructor" << endl;}
C(const C& a) {A::operator=(a); cout << "C copy constructor" << endl;}
void operator=(const C& a) {A::operator=(a); cout << "C copy operator" <<
endl;}
void set(int i) {m = i;}
int get() {return m;}
};

class D : public C
{
public:
// D() {cout << "D default constructor" << endl;}
// D(const D& a) :C(a) {cout << "D copy constructor" << endl;}
// void operator=(const D& a) {C::operator=(a); cout << "D copy operator"
<< endl;}
};

// La déclaration explicite des constructeurs est imposé
// par HP-UX aCC mais pas par gcc...


int main(int argc, char* argv[])
{
A a; B b; C c; D d;
a.m = 1; b.m = 2;
c.set(3); d.set(4);

cout << "-------------------" << endl;
A a2(a); cout << a2.m << endl;

cout << "-------------------" << endl;
B b2(b); cout << b2.m << endl;

cout << "-------------------" << endl;
C c2(c); cout << c2.get() << endl;

cout << "-------------------" << endl;
D d2(d); cout << d2.get() << endl;
}

Error 182: "main.cpp", line 252 # "D::D(const D &)" cannot access public
member "A::A(const A &)".

Lequel à raison ?

3 réponses

Avatar
Loïc Joly
Frédéric Gourul wrote:
Bonjour à tous.

En faisant quelques tests pour règler un problème d'appel de
constructeur avec un héritage virtuel, je me suis appercu que
l'héritage privé de la classe B gênait mon compilateur lors de la
construction par copie de la classe D. Cela m'oblige à déclarer
explicitement le constructeur de copie alors que celui par défaut me
convenait parfaitement.

J'ai testé le même code avec gcc qui lui ne dit rien... Je testerai
le même code avec VC7 ce soir pour voir ce qu'il en dit.


VC8 demande aussi une version explicite. J'ai intuitivement l'impression
qu'ils n'ont pas tort, mais je n'arrive pas à déduire ça de la norme.
Tout ce que j'ai vu, c'est :

All subobjects representing virtual base classes are initialized by
the constructor of the most derived class (1.8). If the constructor
of the most derived class does not specify a meminitializer for a
virtual base class V, then V’s default constructor is called to
initialize the virtual base class subobject. If V does not have an
accessible default constructor, the initialization is illformed. A
meminitializer naming a virtual base class shall be ignored during
execution of the constructor of any class that is not the most
derived class.


Mais j'ai un peu de mal à en déduire comment ça marche avec du private.

PS : Au fait, le constructeur de C, je l'aurais plutôt écrit (sans
certitude) :

C(const C& a) : A(a), B(a){cout << "C copy constructor" << endl;}

PPS : Une structure d'héritage comme ça, c'est dans un vrai programme ?

--
Loïc

Avatar
Jean-Marc Bourguet
"Frédéric Gourul" writes:

// La déclaration explicite des constructeurs est imposé
// par HP-UX aCC mais pas par gcc...


Je ne vois pas de raison de le faire, et como ne le demande
pas.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Frédéric Gourul
"Loïc Joly" a écrit dans le message de news:
ch47vj$5t8$
Frédéric Gourul wrote:
Bonjour à tous.


PS : Au fait, le constructeur de C, je l'aurais plutôt écrit (sans
certitude) :

C(const C& a) : A(a), B(a){cout << "C copy constructor" << endl;}


Ben justement... c'est comme ca que je l'avais écrit au départ. Ca
fonctionne pour la classe C, mais comme ca, la classe D doit aussi appleler
explicitement le constructeur de A, sinon la construction par copie ne fait
rien du tout :(

PPS : Une structure d'héritage comme ça, c'est dans un vrai programme ?


Elle va l'être, oui. C'est le seul endroit où j'ai utilisé l'héritage
virtuel, mais je trouve que la construction est beaucoup plus propre et
beaucoup plus évolutive comme cela.

La classe A, c'est la classe de base, elle contient l'objet sur lequel on va
faire des operations.
La (les) classes B, ce sont des propriétés (implémentations) sur la base de
A
La (les) classes C, ce sont des objets qui sont constitués d'une ou
plusieurs propriétés sur A

L'utilisateur lui ne connait et ne manipule que les classes de niveau C.
Mais rien ne l'empêche d'en faire une dérivation... Je voulais donc règler
le problème évoqué plus haut pour les classes de niveau D.