OVH Cloud OVH Cloud

Heritage d'une classe...

25 réponses
Avatar
Adrien Constant
Ou ne sait quel nom cela porte, mais considérant l'exemple suivant :

#include <stdio.h>

class Bla
{
public:
int x;
class T;
};

class Bla::T : public Bla
{
public:
int h;
void aff(){printf("%d %d\n", x, h);}
};

int main()
{
Bla *bla = new Bla;
bla->x = 5;
Bla::T *t = new Bla::T;
t->h = 7;
t->aff();
}

Cela affiche évidemment x=undef=0 et h=7, hors comment faire pour que
l'objet qui a créé la class Bla soit utilité pour créer celui de la
classe Bla::T et qu'on obtienne x=5 et h=7 ?

Merci.

Adrien Constant

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
Adrien Constant writes:

Voilà.. si qq'un arrive à me comprendre ce me serait vraiment très très
utile de savoir :)


Je ne te comprends pas vraiment. A nouveau j'ai l'impression que tu
veux les "inner class" de Java auquel cas la solution d'avoir un
membre dans World referencant le Hello que tu veux.

Sinon, donne un exemple complet de ce que tu veux dans un langage qui
l'autorise plutot que du simili C++ avec une semantique a deviner
puisque le probleme pour le moment est justement de trouver la maniere
C++ d'exprimer ta semantique (un probleme accessoire mais peut-etre
tout aussi important est de comprendre pourquoi tu veux faire ca).

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
Christophe Lephay
Adrien Constant wrote:
class Bla
{
public:
int x;
class T;
};

class Bla::T : public Bla
{
public:
int h;
void aff(){printf("%d %dn", x, h);}
};

int main()
{
Bla *bla = new Bla;
bla->x = 5;
Bla::T *t = new Bla::T;
t->h = 7;
t->aff();
}

Cela affiche évidemment x=undef=0 et h=7, hors comment faire pour que
l'objet qui a créé la class Bla soit utilité pour créer celui de la
classe Bla::T et qu'on obtienne x=5 et h=7 ?


Ton problème, c'est que tu as deux objets Bla créés : un avec ton ne Bla, et
l'autre avec ton new Bla::T (qui crée bien un Bla par héritage).

Ce que tu veux faire n'est pas clair : veux-tu la création de deux objets
(auquel cas il est normal que les deux objets aient des x différents) ou un
seul (auquel cas soit l'héritage est une erreur de conception, soit il ne
faut pas créer d'objet Bla).

Si tu veux qu'un "sous-objet" garde une référence sur un autre, l'héritage
est une erreur :

class Bla {
int x;
public:
class T {
int h;
Bla * parent;
public:
T( const Bla& un_bla ) : parent( &un_bla ) {}
};
};

De cette manière, la référence au parent est fournie lors de la construction
de l'objet T (attention si les durées de vie des deux objets diffèrent).

Si tu veux que le "sous-objet" crée une copie d'un objet parent, alors tu
peux utiliser l'héritage, mais il faut toujours fournir le parent au
constructeur :

class Bla {
int x;
public:
class T : public Bla {
int h;
public:
T( const Bla& un_bla ) : Bla( un_bla ) {} // il faut un cteur-copieur
dans Bla
};
};

Si les deux objets (Bla et T::Bla) sont forcément liés, il est alors plus
avisé de faire en sorte que le "parent" connaisse l'enfant, de manière à le
détruire lorsque lui-même est détruit.

Bref, l'objectif que tu poursuis n'est pas du tout clair, essaie de
réfléchir un peu plus précisément à ce que tu veux faire, avant de penser à
comment tu veux le faire...

Chris

Avatar
Gabriel Dos Reis
Adrien Constant writes:

| et moi j'avais entendu Perl est l'implémentation de perl

tu as mal entendu.

-- Gaby
Avatar
kanze
Adrien Constant wrote in message
news:<3f8d39a7$0$20647$...

Non ce n'est pas tordu cela est courant dans certains langages.

struct T {};
struct Bla { struct T *t; };


Ça, on peut bien le faire en C++ aussi:-).

Et bien je veux faire pareil avec des classes tout en ayant T qui
puisse accéder aux méthodes / variables publiques de Bla.


Mais quelle instance de Bla ? La toute est là. Si c'est une instance
propre à lui, l'héritage peut servir (bien qu'on préfère en général
l'appartenance), et il faudrait initialiser l'instance lors de sa
création. Si c'est une instance existante, il faut bien d'une part,
spécifier laquelle lors de la création, et de l'autre, passer par des
pointeurs ou des références, puisque tu as potentiellement affaire à un
rapport n->1 -- plusieurs T peuvent « contenir » le même Bla.

C'est évidemment possible de passer par une référence de Bla mais je
pense qu'il est possible de faire autrement, puisque c'est a ca que
sert l'héritage ai-je cru comprendre.


Je crois que tu as mal compris. L'héritage, dans son utilisation la plus
classique, sert à définir un rapport « estUn » -- si T hérite de Bla, T
est un Bla, et peut servir n'importe où que peut servir un Bla. (Il y a
bien d'autres utilisations de l'héritage, mais commençons par les choses
simples.)

L'intéret n'est autre que pour la clareté du code, le plus simple est
effectivement de faire deux classes séparées. Je ne vois pas ce qu'il
y a de tordu a avoir une classe dans une classe et vouloir en hériter.


Ce n'est pas ce qu'il y a de plus fréquent, mais il y a effectivement
des cas où ça peu servir. Mais pas pour ce que tu sembles vouloir faire.

class Bla {
public:
int x, y, z;
int *fd_list;
}

On peut tout simplement avoir besoin d'une classe spéciale au lieu
d'utiliser int *fd_list dans que cas on peut créer

class FdList {
public:
FdList();
~FdList();
Add(int fd);
Remove(int fd);
int *fd_list;
}

et décider de faire new Bla::FdList[15];


Certes. Mais quel rapport avec ce que tu essaies de faire.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
Christophe Lephay
wrote:
Je ne vois pas ce qu'il
y a de tordu a avoir une classe dans une classe et vouloir en
hériter.


Ce n'est pas ce qu'il y a de plus fréquent, mais il y a effectivement
des cas où ça peu servir. Mais pas pour ce que tu sembles vouloir
faire.


Tu penses à quoi, en l'occurence ?
(simple curiosité)

Chris


Avatar
Adrien Constant
Christophe Lephay wrote:
Adrien Constant wrote:

class Bla
{
public:
int x;
class T;
};

class Bla::T : public Bla
{
public:
int h;
void aff(){printf("%d %dn", x, h);}
};

int main()
{
Bla *bla = new Bla;
bla->x = 5;
Bla::T *t = new Bla::T;
t->h = 7;
t->aff();
}

Cela affiche évidemment x=undef=0 et h=7, hors comment faire pour que
l'objet qui a créé la class Bla soit utilité pour créer celui de la
classe Bla::T et qu'on obtienne x=5 et h=7 ?



Ton problème, c'est que tu as deux objets Bla créés : un avec ton ne Bla, et
l'autre avec ton new Bla::T (qui crée bien un Bla par héritage).

Ce que tu veux faire n'est pas clair : veux-tu la création de deux objets
(auquel cas il est normal que les deux objets aient des x différents) ou un
seul (auquel cas soit l'héritage est une erreur de conception, soit il ne
faut pas créer d'objet Bla).

Si tu veux qu'un "sous-objet" garde une référence sur un autre, l'héritage
est une erreur :

class Bla {
int x;
public:
class T {
int h;
Bla * parent;
public:
T( const Bla& un_bla ) : parent( &un_bla ) {}
};
};

De cette manière, la référence au parent est fournie lors de la construction
de l'objet T (attention si les durées de vie des deux objets diffèrent).

Si tu veux que le "sous-objet" crée une copie d'un objet parent, alors tu
peux utiliser l'héritage, mais il faut toujours fournir le parent au
constructeur :

class Bla {
int x;
public:
class T : public Bla {
int h;
public:
T( const Bla& un_bla ) : Bla( un_bla ) {} // il faut un cteur-copieur
dans Bla
};
};

Si les deux objets (Bla et T::Bla) sont forcément liés, il est alors plus
avisé de faire en sorte que le "parent" connaisse l'enfant, de manière à le
détruire lorsque lui-même est détruit.

Bref, l'objectif que tu poursuis n'est pas du tout clair, essaie de
réfléchir un peu plus précisément à ce que tu veux faire, avant de penser à
comment tu veux le faire...

Chris




En fait c'est très clair dans ma tete c'est juste que je ne sais pas le
faire en C++ et que je ne sais trop comment l'expliquer. Personne n'a
l'air de vraiment comprendre ce que je veux dire.

class Bla {
int x;
public:
class T {
int h;
Bla * parent;
public:
T( const Bla& un_bla ) : parent( &un_bla ) {}
};
};


Voilà je pense qu'en gros c'est ça, sauf que comme je l'avais marqué
dans une de mes réponse je voulais savoir si il est possible de le faire
_sans_ passer une référence de la classe parent. Etant donné que la
class T fait partie de la classe Bla je pensais qu'il était possible
qu'il soit assigné à Bla::T un parent lors de la construction de l'objet.
Un syntaxe qui n'existe pas en C++ mais qui aurait pu etre du genre:

Bla *bla = new Bla[10]; // 10 classes Bla, normal
Bla::T *t = new Bla::T bla[5]->T[3];
// 3 classes Bla::T crées à partir du 5e élément de *bla
Je sais c'est absurde en tout cas en C++ mais c'est pour essayer de
faire comprendre ce que je souhaiterais faire.

En fait dans mon cas précis ca ressemble à ca :

class Server
{
public:
[...]
int fd_sock;
class Client
{
public:
int fd_client;
// blabla
};
};


hors, la class Client a besoin d'accéder aux variables de Server.

On crée un (ou plusieurs serveurs)
Server *server = new Server;

Puis dans le cas ou on voudrait avoir SOMAXCONN max clients :
Server::Client *clients = new Server::Client[SOMAXCONN];

Donc en sachant que les clients doivent avoir accès à Server::fd_sock et
autres variables / fonctions publiques de Server, et que Server devrait
avoir accès aux variables / fctions publiques de Server::Client. En fait
ca revient strictement au meme que d'avoir une seule classe :

class Server
{
public:
int fd_sock;
int *fd_client; // ici du coup on aura besoin d'un tableau
[...]
};

et de faire

Server *server = new Server;
server->fd_client = new int[SOMAXCONN];

sauf que vous l'aurez compris, pour des soucis de logique de code et
surtout pour simplifier les choses (il faut chaque fois créer des
tableaux 2d il est bcp plus simple d'allouer n classes et d'accéder
directement à l'élément n, sinon avec beaucoup de variables et de
fonctions ca peut devenir assez bordélique) je préfère avoir une class
Server et une class Client séparés.

On pourrait également faire

class Server {};
class Client {};

Mais vu que la class Client n'a aucune raison d'exister seule (il lui
faut un père) je ne trouve pas ça très logique de la séparer de son parant.

Voilà c'est un peu long... merci d'avoir pris le temps de lire.


Avatar
Christophe Lephay
Adrien Constant wrote:
Voilà je pense qu'en gros c'est ça, sauf que comme je l'avais marqué
dans une de mes réponse je voulais savoir si il est possible de le
faire _sans_ passer une référence de la classe parent. Etant donné
que la
class T fait partie de la classe Bla je pensais qu'il était possible
qu'il soit assigné à Bla::T un parent lors de la construction de
l'objet. Un syntaxe qui n'existe pas en C++ mais qui aurait pu etre
du genre:


Que la classe T soit définie dans Bla n'indique rien sur les relations entre
d'éventuelles (et surtout multiples !) instances de ces deux classes.

Si c'est une relation 1-1, alors l'héritage suffit.

Avec :

class Bla
{
public:
int x;
};

class T : public Bla
{
public:
int h;
};

en créant un objet de type T, un objet de type Bla est automatiquement créé
:

T objet;
objet.x = 5; objet.h = 10;


Bla *bla = new Bla[10]; // 10 classes Bla, normal
Bla::T *t = new Bla::T bla[5]->T[3];
// 3 classes Bla::T crées à partir du 5e élément de *bla
Je sais c'est absurde en tout cas en C++ mais c'est pour essayer de
faire comprendre ce que je souhaiterais faire.


Ben c'est encore raté lol

En fait dans mon cas précis ca ressemble à ca :

class Server
{
public:
[...]
int fd_sock;
class Client
{
public:
int fd_client;
// blabla
};
};


hors, la class Client a besoin d'accéder aux variables de Server.

On crée un (ou plusieurs serveurs)
Server *server = new Server;

Puis dans le cas ou on voudrait avoir SOMAXCONN max clients :
Server::Client *clients = new Server::Client[SOMAXCONN];

Donc en sachant que les clients doivent avoir accès à Server::fd_sock
et autres variables / fonctions publiques de Server, et que Server
devrait avoir accès aux variables / fctions publiques de
Server::Client. En fait ca revient strictement au meme que d'avoir
une seule classe :

class Server
{
public:
int fd_sock;
int *fd_client; // ici du coup on aura besoin d'un tableau
[...]
};

et de faire

Server *server = new Server;
server->fd_client = new int[SOMAXCONN];

sauf que vous l'aurez compris, pour des soucis de logique de code et
surtout pour simplifier les choses (il faut chaque fois créer des
tableaux 2d il est bcp plus simple d'allouer n classes et d'accéder
directement à l'élément n, sinon avec beaucoup de variables et de
fonctions ca peut devenir assez bordélique) je préfère avoir une class
Server et une class Client séparés.

On pourrait également faire

class Server {};
class Client {};

Mais vu que la class Client n'a aucune raison d'exister seule (il lui
faut un père) je ne trouve pas ça très logique de la séparer de son
parant.


class serveur
{
class client
{
};

std::vector< client > clients;

public:
...
};

C'est une erreur d'analyse de faire hériter client de serveur. Pour
reprendre l'explication de James, un client *n'est pas* un serveur. De plus,
un même serveur va gérer plusieurs clients. En fait, la classe serveur doit
gérer une liste de connections clientes, et c'est une relation
d'appartenance, pas une relation "est un".

A toi de voir si la classe client doit être accessible de l'extérieur ou
non...

Chris

Avatar
Adrien Constant
Christophe Lephay wrote:
Si c'est une relation 1-1, alors l'héritage suffit.

Avec :

class Bla
{
public:
int x;
};

class T : public Bla
{
public:
int h;
};

en créant un objet de type T, un objet de type Bla est automatiquement créé
:

T objet;
objet.x = 5; objet.h = 10;


Le seul problème c'est que je ne veux pas créer autant d'objets class
Bla que class T, ici c'est un ration 1:1.




Bla *bla = new Bla[10]; // 10 classes Bla, normal
Bla::T *t = new Bla::T bla[5]->T[3];
// 3 classes Bla::T crées à partir du 5e élément de *bla
Je sais c'est absurde en tout cas en C++ mais c'est pour essayer de
faire comprendre ce que je souhaiterais faire.



Ben c'est encore raté lol


Je finis par désespèrer.



En fait dans mon cas précis ca ressemble à ca :

class Server
{
public:
[...]
int fd_sock;
class Client
{
public:
int fd_client;
// blabla
};
};




C'est une erreur d'analyse de faire hériter client de serveur. Pour
reprendre l'explication de James, un client *n'est pas* un serveur. De plus,
un même serveur va gérer plusieurs clients. En fait, la classe serveur doit
gérer une liste de connections clientes, et c'est une relation
d'appartenance, pas une relation "est un".

A toi de voir si la classe client doit être accessible de l'extérieur ou
non...

Chris




Non un client n'est pas un serveur (c'est meme plutot son contraire..)
mais le client n'existe pas sans le serveur. C'est pour ca que je veux
que l'object class Client ne soit crée que par class Serveur. Et c'est
justement parceque un seul serveur doit gérer plusieurs clients que je
veux pouvoir créer le nbre que je souhaite de chacun.

Meme dans le cas ou ce serait "mieux" de faire deux classes séparées, je
voudrais quand meme des exemples de class qui comportent des classes, et
essayer de trouver ce que j'essaie de faire sans succès depuis qq heures..


Avatar
Laurent DELEPINE
Adrien Constant wrote:

Non un client n'est pas un serveur (c'est meme plutot son contraire..)
mais le client n'existe pas sans le serveur. C'est pour ca que je veux
que l'object class Client ne soit crée que par class Serveur. Et c'est
justement parceque un seul serveur doit gérer plusieurs clients que je
veux pouvoir créer le nbre que je souhaite de chacun.

Meme dans le cas ou ce serait "mieux" de faire deux classes séparées, je
voudrais quand meme des exemples de class qui comportent des classes, et
essayer de trouver ce que j'essaie de faire sans succès depuis qq heures..


J'ai probleme de comprehension. Tu crées un programme client/serveur
avec communication par reseau. Dans ce cas, les instances de classes
peuvent se trouver sur deux ordinateur differents. C'est ca ?

A+

LD

Avatar
Loïc Joly
Adrien Constant wrote:


Non un client n'est pas un serveur (c'est meme plutot son contraire..)
mais le client n'existe pas sans le serveur. C'est pour ca que je veux
que l'object class Client ne soit crée que par class Serveur. Et c'est
justement parceque un seul serveur doit gérer plusieurs clients que je
veux pouvoir créer le nbre que je souhaite de chacun.


Pourquoi donc ne pas faire deux classes voisines, donner à la classe
Client un constructeur privé (afin d'assurer que personne ne pourra
créer de client), et la déclarer friend de Serveur (sauf la classe
Serveur). Alors, la classe Serveur contiendra un tableau (std::vector,
par exemple) de Clients.

--
Loïc

1 2 3