OVH Cloud OVH Cloud

this dans un constructeur

11 réponses
Avatar
Marc
Question simple : est-ce qu'on peut utiliser this dans un constructeur ou
c'est dangereux ?
Pire :
est-ce que dans le constructeur je peux écrire par exemple
throw std::invalid_argument("conversion de "+this->get_typename()+" en
MonObjet impossible.");
où ici get_typename() est une fonction virtuelle.
Mon compilo accepte tous çà à la compilation.
Ce cas ne devrait pas se produire mais au cas où...
Marc

10 réponses

1 2
Avatar
Fabien LE LEZ
On Thu, 28 Oct 2004 17:24:09 +0200, "Marc" :

Question simple : est-ce qu'on peut utiliser this dans un constructeur ou
c'est dangereux ?


Pas de souci, il faut juste se rappeler que dans C::C(), "this" est de
type C*, même si on est en train de construire un objet d'un type
dérivé.

throw std::invalid_argument("conversion de "+this->get_typename()+" en
MonObjet impossible.");
où ici get_typename() est une fonction virtuelle.


Le fait que get_typename() soit virtuelle ne changera rien.
Et hors cas spéciaux dans les templates, écrire "this->" ne sert pas à
grand-chose -- this->get_typename() est équivalent à get_typename().

struct B
{
B() { Affiche(); }
void f() { Affiche(); }
virtual void Affiche() { cout << "B" << endl; }
};

struct D: B
{
virtual void Affiche() { cout << "D" << endl; }
};

int main()
{
D d; /* affiche "B", car dans B::B(), l'objet est de type B.
(Peut-être est-ce un abus de langage, mais c'est l'idée.) */
d.f(); /* affiche "D", car d est totalement construit, et donc de
type D. */
}


--
;-)

Avatar
Marc
Le fait que get_typename() soit virtuelle ne changera rien.
Et hors cas spéciaux dans les templates, écrire "this->" ne sert pas à
grand-chose -- this->get_typename() est équivalent à get_typename().


c'est vrai, mais la fatigue aidant, on écrit parfois des trivialités...

struct B
{
B() { Affiche(); }
void f() { Affiche(); }
virtual void Affiche() { cout << "B" << endl; }
};

struct D: B
{
virtual void Affiche() { cout << "D" << endl; }
};


si je fais:

struct D: B
{
D() { Affiche(); }
virtual void Affiche() { cout << "D" << endl; }
};
D d;
ça donne quoi dans ce cas ?
pourquoi pas une première fois "B" (lors de l'appel implicite du
constructeur de la classe de base)
puis "D", cette fois dans le constructeur de D

Avatar
Fabien LE LEZ
On Thu, 28 Oct 2004 18:19:51 +0200, "Marc" :

ça donne quoi dans ce cas ?


Si jamais tu as un compilo sous la main, le mieux est d'essayer...

une première fois "B" (lors de l'appel implicite du
constructeur de la classe de base)
puis "D", cette fois dans le constructeur de D


Yep, c'est bien ça. Note que si Affiche() n'était pas virtuelle, le
résultat serait le même.



--
;-)

Avatar
drkm
"Marc" writes:

ça donne quoi dans ce cas ?
pourquoi pas une première fois "B" (lors de l'appel implicite du
constructeur de la classe de base)
puis "D", cette fois dans le constructeur de D


Ben c'est le cas, non ?

--drkm

Avatar
Marc
Tout est clair désormais.
Marc
Avatar
Marc
J'ai un cas de figure un peu subtil en rapport avec ce qu'on vient de dire.

class A {

protected :
A(const A&) { if (isA()) ...}
B *objet_derive;
virtual bool isA() { return true;}

};

class B : public A {

B() : A(*this)
B(const &A) : A(*this), value(false) {}

protected :

virtual bool isA() { return false;}
bool value;

}

l'objet B ayant un constructeur par défaut, je peux créer des objets A et
pourtant la classe A
ne comporte qu'un constructeur de copie.
Logiquement, on retombe sur le casse-tête de la poule et de l'oeuf et on
peux dire que l'on a la poule sans créer l'oeuf !

ça marche sur mon compilo.
Petite question subsidiaire : dans le constructeur de A, j'utilise isA()
pour savoir si j'ai un objet de la classe de base. Pour moi, le code est +
lisible et plus concis qu'un !dynamic_cast<B*>(&A).
Est-ce que c'est aussi performant ou est-ce que ça rallonge le temps
d'execution ?

Bonne nuit.
Marc
Avatar
drkm
"Marc" writes:

l'objet B ayant un constructeur par défaut, je peux créer des objets A et
pourtant la classe A
ne comporte qu'un constructeur de copie.


Et alors ? Tu as un constructeur, c'est suffisant.

Logiquement, on retombe sur le casse-tête de la poule et de l'oeuf et on
peux dire que l'on a la poule sans créer l'oeuf !


Je ne comprends pas.

ça marche sur mon compilo.
Petite question subsidiaire : dans le constructeur de A, j'utilise isA()
pour savoir si j'ai un objet de la classe de base.


Ce qui renverra toujours vrai. On te l'a dit, dans un constructeur,
les mécanismes virtuels ne mrchent pas. Le type dynamique de `this' y
est toujours, comme dans le detructeur, égal au type statique.

Pour moi, le code est +
lisible et plus concis qu'un !dynamic_cast<B*>(&A).
Est-ce que c'est aussi performant ou est-ce que ça rallonge le temps
d'execution ?


Ce n'est pas l'important. L'important et d'avoir un code qui
fonctionne. En général, ce genre de chose est symptomatique d'une
mauvaise conception. Que veux-tu faire, exactement ?

--drkm

Avatar
Horst Kraemer
"Marc" wrote:

J'ai un cas de figure un peu subtil en rapport avec ce qu'on vient de dire.

class A {

protected :
A(const A&) { if (isA()) ...}


if (isA()) est toujours 'true' dans un constructeur de A parce qu'en
C++ le type de *this dans un constructeur de la classe A est toujours
'A'. (En d'autres langages OO comme Delphi c'est différent). Donc
isA() dans un constructeur de A veut toujours dire A::isA(),


B *objet_derive;
virtual bool isA() { return true;}

};

class B : public A {

B() : A(*this)
B(const &A) : A(*this), value(false) {}

protected :

virtual bool isA() { return false;}
bool value;

}


--
Horst

--
Lâche pas la patate!

Avatar
drkm
writes:

drkm wrote in message
news:...

Ce qui renverra toujours vrai. On te l'a dit, dans un constructeur,
les mécanismes virtuels ne mrchent pas. Le type dynamique de `this' y
est toujours, comme dans le detructeur, égal au type statique.


En revanche, étant donné que tous les constructeurs de A sont protégés,
il ne doit pas avoir besoin de se poser la question : A ne peut être
qu'une classe de base, puisqu'il n'y a que des classes dérivées qui
peuvent en construire un.


Tiens, oui. Je n'avais pas relevé ce point. Lorsque je vois un tel
code, utilisant une fonction membre virtuelle `isUnType()', ma
première réaction est de me dire : « Houla ! Où est l'erreur de
conception ? ».

Y aurait-il des utilisations légitimes de cette technique ?

--drkm


Avatar
drkm
"Marc" writes:

Tiens, oui. Je n'avais pas relevé ce point. Lorsque je vois un tel
code, utilisant une fonction membre virtuelle `isUnType()', ma
première réaction est de me dire : « Houla ! Où est l'erreur de
conception ? ».

Y aurait-il des utilisations légitimes de cette technique ?


avant de casser, faut lire la question ou ne rien dire..


?

Je concède que le petit bout de code if (isA()) ...dans le constructeur de
A renverra toujours true et n'a aucun intérêt.Cependant, là n'était pas la
question !


Ah, ben si ce n'était pas la question ...

En fait il y en avait deux :
- je constatait avec surprise qu'on pouvait avoir une classe n'ayant qu'un
constructeur de copie. C'est évident pour les surdoués, mais pas pour moi.
- isA() utilise le polymorphisme, exactement comme dynamic_cast<> je suppose
!


Non. Avec dynamic_cast<>, tu essayes de convertir un pointeur ou
une référence à un objet d'un certain type en un pointeur ou une
référence au même objet mais vu d'un type différent. Au lieu de
`isA()', avec lequel tu feras des erreurs, tu peux utiliser `typeid'.

--drkm


1 2