Laurent Deniau writes:Pour obtenir cet alias, il faut jouer a l'appenti sorcier avec des
reinterpret_cast, d'ou UB. Ni static_cast, ni dynamic_cast ne
permettent d'obtenir cet d'alias derive de this.
Les alias peuvent provenir de l'appelant. Avec de l'heritage multiple,
ce peut un pointeur sur une base deja contruite passe en parametre.
Pas d'UB ni de jeux dangereux, mais bien qqch qu'on peut vouloir faire
raisonnablement:
struct A {
virtual void f();
};
struct D_A {
virtual void f();
};
struct B {
B(A*p) { p->f(); }
};
struct F: public D_A, B {
F(): B(this) {} // this comme D_A est valide car construit avant
};
Eh non, l'appel virtuel dans B::B() est indefini!
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
Pour obtenir cet alias, il faut jouer a l'appenti sorcier avec des
reinterpret_cast, d'ou UB. Ni static_cast, ni dynamic_cast ne
permettent d'obtenir cet d'alias derive de this.
Les alias peuvent provenir de l'appelant. Avec de l'heritage multiple,
ce peut un pointeur sur une base deja contruite passe en parametre.
Pas d'UB ni de jeux dangereux, mais bien qqch qu'on peut vouloir faire
raisonnablement:
struct A {
virtual void f();
};
struct D_A {
virtual void f();
};
struct B {
B(A*p) { p->f(); }
};
struct F: public D_A, B {
F(): B(this) {} // this comme D_A est valide car construit avant
};
Eh non, l'appel virtuel dans B::B() est indefini!
Laurent Deniau writes:Pour obtenir cet alias, il faut jouer a l'appenti sorcier avec des
reinterpret_cast, d'ou UB. Ni static_cast, ni dynamic_cast ne
permettent d'obtenir cet d'alias derive de this.
Les alias peuvent provenir de l'appelant. Avec de l'heritage multiple,
ce peut un pointeur sur une base deja contruite passe en parametre.
Pas d'UB ni de jeux dangereux, mais bien qqch qu'on peut vouloir faire
raisonnablement:
struct A {
virtual void f();
};
struct D_A {
virtual void f();
};
struct B {
B(A*p) { p->f(); }
};
struct F: public D_A, B {
F(): B(this) {} // this comme D_A est valide car construit avant
};
Eh non, l'appel virtuel dans B::B() est indefini!
Laurent Deniau writes:Jean-Marc Bourguet wrote:Laurent Deniau writes:Jean-Marc Bourguet wrote:Laurent Deniau writes: Pendant
l'execution du constructeur et du destructeur, l'objet est du
type de la classe construite (et non de la classe la plus
derivee). Appeler un membre virtuel sur this a un comportement
defini: la fonction sera celle de la classe construite ou de
l'ancetre la fournissant (donc c'est un probleme si elle est
pure). Appeler un membre virtuel a travers d'un alias de this qui
n'est pas du type construit ou d'un de ses descendants est
indefini.
Ok.
Pour obtenir cet alias, il faut jouer a l'appenti sorcier avec des
reinterpret_cast, d'ou UB. Ni static_cast, ni dynamic_cast ne
permettent d'obtenir cet d'alias derive de this.
Les alias peuvent provenir de l'appelant. Avec de l'heritage
multiple, ce peut un pointeur sur une base deja contruite passe en
parametre. Pas d'UB ni de jeux dangereux, mais bien qqch qu'on
peut vouloir faire raisonnablement:
struct A {
virtual void f();
};
struct D_A {
virtual void f();
};
struct B {
B(A*p) { p->f(); }
};
struct F: public D_A, B {
F(): B(this) {} // this comme D_A est valide car construit avant
};
Eh non, l'appel virtuel dans B::B() est indefini!
Pourquoi? p dans B::B() est de type effectif F* (mais this est de
type B*). p->f() vas donc invoquer legalement D_A::f() sur un this
de type F*. Ou vois-tu un alias de this en tant que B*?
p et this designent le meme objet (le F en cours de construction)
p n'est pas un B (ou une de ses bases) c'est donc un comportement
indefini.
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
Jean-Marc Bourguet wrote:
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
Jean-Marc Bourguet wrote:
Laurent Deniau <Laurent.Deniau@cern.ch> writes: Pendant
l'execution du constructeur et du destructeur, l'objet est du
type de la classe construite (et non de la classe la plus
derivee). Appeler un membre virtuel sur this a un comportement
defini: la fonction sera celle de la classe construite ou de
l'ancetre la fournissant (donc c'est un probleme si elle est
pure). Appeler un membre virtuel a travers d'un alias de this qui
n'est pas du type construit ou d'un de ses descendants est
indefini.
Ok.
Pour obtenir cet alias, il faut jouer a l'appenti sorcier avec des
reinterpret_cast, d'ou UB. Ni static_cast, ni dynamic_cast ne
permettent d'obtenir cet d'alias derive de this.
Les alias peuvent provenir de l'appelant. Avec de l'heritage
multiple, ce peut un pointeur sur une base deja contruite passe en
parametre. Pas d'UB ni de jeux dangereux, mais bien qqch qu'on
peut vouloir faire raisonnablement:
struct A {
virtual void f();
};
struct D_A {
virtual void f();
};
struct B {
B(A*p) { p->f(); }
};
struct F: public D_A, B {
F(): B(this) {} // this comme D_A est valide car construit avant
};
Eh non, l'appel virtuel dans B::B() est indefini!
Pourquoi? p dans B::B() est de type effectif F* (mais this est de
type B*). p->f() vas donc invoquer legalement D_A::f() sur un this
de type F*. Ou vois-tu un alias de this en tant que B*?
p et this designent le meme objet (le F en cours de construction)
p n'est pas un B (ou une de ses bases) c'est donc un comportement
indefini.
Laurent Deniau writes:Jean-Marc Bourguet wrote:Laurent Deniau writes:Jean-Marc Bourguet wrote:Laurent Deniau writes: Pendant
l'execution du constructeur et du destructeur, l'objet est du
type de la classe construite (et non de la classe la plus
derivee). Appeler un membre virtuel sur this a un comportement
defini: la fonction sera celle de la classe construite ou de
l'ancetre la fournissant (donc c'est un probleme si elle est
pure). Appeler un membre virtuel a travers d'un alias de this qui
n'est pas du type construit ou d'un de ses descendants est
indefini.
Ok.
Pour obtenir cet alias, il faut jouer a l'appenti sorcier avec des
reinterpret_cast, d'ou UB. Ni static_cast, ni dynamic_cast ne
permettent d'obtenir cet d'alias derive de this.
Les alias peuvent provenir de l'appelant. Avec de l'heritage
multiple, ce peut un pointeur sur une base deja contruite passe en
parametre. Pas d'UB ni de jeux dangereux, mais bien qqch qu'on
peut vouloir faire raisonnablement:
struct A {
virtual void f();
};
struct D_A {
virtual void f();
};
struct B {
B(A*p) { p->f(); }
};
struct F: public D_A, B {
F(): B(this) {} // this comme D_A est valide car construit avant
};
Eh non, l'appel virtuel dans B::B() est indefini!
Pourquoi? p dans B::B() est de type effectif F* (mais this est de
type B*). p->f() vas donc invoquer legalement D_A::f() sur un this
de type F*. Ou vois-tu un alias de this en tant que B*?
p et this designent le meme objet (le F en cours de construction)
p n'est pas un B (ou une de ses bases) c'est donc un comportement
indefini.
Laurent Deniau writes:c'est dans F::F() que tu crees l'alias en appellant B::B() avec deux
this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le UB:
struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
Ce code marchera (contraitement a ton exemple qui met bien les point
sur les 'i' ;-), mais je pense que la norme lui attribue quand meme
un UB, p etant un alias sur D* mais de type effectif A* au meme
titre que this...
Je crois que c'est bien defini.
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
c'est dans F::F() que tu crees l'alias en appellant B::B() avec deux
this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le UB:
struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
Ce code marchera (contraitement a ton exemple qui met bien les point
sur les 'i' ;-), mais je pense que la norme lui attribue quand meme
un UB, p etant un alias sur D* mais de type effectif A* au meme
titre que this...
Je crois que c'est bien defini.
Laurent Deniau writes:c'est dans F::F() que tu crees l'alias en appellant B::B() avec deux
this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le UB:
struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
Ce code marchera (contraitement a ton exemple qui met bien les point
sur les 'i' ;-), mais je pense que la norme lui attribue quand meme
un UB, p etant un alias sur D* mais de type effectif A* au meme
titre que this...
Je crois que c'est bien defini.
Laurent Deniau wrote in messageDonc quand Gaby dit que un B* devient un A* en entrant dans A::~A(),
il a complement raison.
Un B* devient un A* dans toute fonction member de A. Quel rapport ?
Quand il y a résolution dynamique d'une fonction, la fonction appelée
dépend du type dynamique de l'objet pointé, non du type du pointeur. Ce
qui importe ici, c'est que le type dynamique de l'objet change quand on
entre dans le destructeur. Le type du pointeur n'a pas beaucoup
d'importance.
Ce qui veut dire ensuite que la resolution des
methodes (virtuelle ou non) reste inchange: pas de semantique
particuliere dans les ctor/dtor.
Tout à fait. On résoud l'appel selon le type dynamique de l'objet, et
non selon le type du pointeur.
Laurent Deniau <Laurent.Deniau@cern.ch> wrote in message
Donc quand Gaby dit que un B* devient un A* en entrant dans A::~A(),
il a complement raison.
Un B* devient un A* dans toute fonction member de A. Quel rapport ?
Quand il y a résolution dynamique d'une fonction, la fonction appelée
dépend du type dynamique de l'objet pointé, non du type du pointeur. Ce
qui importe ici, c'est que le type dynamique de l'objet change quand on
entre dans le destructeur. Le type du pointeur n'a pas beaucoup
d'importance.
Ce qui veut dire ensuite que la resolution des
methodes (virtuelle ou non) reste inchange: pas de semantique
particuliere dans les ctor/dtor.
Tout à fait. On résoud l'appel selon le type dynamique de l'objet, et
non selon le type du pointeur.
Laurent Deniau wrote in messageDonc quand Gaby dit que un B* devient un A* en entrant dans A::~A(),
il a complement raison.
Un B* devient un A* dans toute fonction member de A. Quel rapport ?
Quand il y a résolution dynamique d'une fonction, la fonction appelée
dépend du type dynamique de l'objet pointé, non du type du pointeur. Ce
qui importe ici, c'est que le type dynamique de l'objet change quand on
entre dans le destructeur. Le type du pointeur n'a pas beaucoup
d'importance.
Ce qui veut dire ensuite que la resolution des
methodes (virtuelle ou non) reste inchange: pas de semantique
particuliere dans les ctor/dtor.
Tout à fait. On résoud l'appel selon le type dynamique de l'objet, et
non selon le type du pointeur.
Jean-Marc Bourguet wrote in message
news:...Laurent Deniau writes:c'est dans F::F() que tu crees l'alias en appellant B::B() avec deux
this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le UB:struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};struct D : A {
D(): A(this) {} // alias
virtual void f();
};Ce code marchera (contraitement a ton exemple qui met bien les point
sur les 'i' ;-), mais je pense que la norme lui attribue quand meme
un UB, p etant un alias sur D* mais de type effectif A* au meme
titre que this...Je crois que c'est bien defini.
§3.8 :
1 The lifetime of an object is a runtime property of the object. The
lifetime of an object of type T begins when:
-- storage with the proper alignment and size for type T is
obtained, and
-- if T is a class type with a non-trivial constructor, the
constructor call has completed.
[...]
5 Before the lifetime of an object has started but after the storage
which the object will occupy has been allocated [...], any pointer
that refers to the storage location where the object will be or was
located may be used but only in limited ways. [...] If the object
will be or was of a non-POD class type, the program has undefined
behavior if:
[...]
-- the pointer is implicitely converted to a pointer to a base
class type, or
[...]
Alors, dans le cas ci-dessus : 1) this est un D*, un pointeur à un objet
avec un type de classe non POD, et 2) l'appel du constructeur de A le
convertit implicitement en pointeur à une base du type. C'est donc un
comportement indéfini.
En fait, je me démande aussi... Indépendamment du paramètre, il faut
bien passer le this au constructeur de base. Est-ce que ça ne compte pas
comme conversion implicite en pointeur à une base aussi ? Si oui, je
dirais qu'on a bien affaire à un défaut dans la norme.
Dans la pratique, je n'ai jamais eu de problème qu'avec des classes de
base virtuelles. En revanche, quand j'ai essayé le suivant :
class MyIStream : private virtual MyStreambuf, public std::istream
...
MyIStream::MyIStream()
: std::istream( this )
{
}
avec au moins un compilateur, le pointeur passé à std::istream n'était
pas valid, c-à-d qu'il ne containait pas l'adresse de l'objet
std::streambuf classe de base de MyStreambuf.
En ôtant la dérivation virtuelle, ça marche partout. Mais le
comportement reste indéfini selon la norme. (Note que la seule chose que
fait std::istream avec le pointeur, c'est de le passer vers sa classe de
base, pour à la fin le stocker dans une variable membre de std::ios. Pas
que ce soit garanti par la norme, mais dans la pratique, c'est comme ça
que ça se passe.)
Jean-Marc Bourguet <jm@bourguet.org> wrote in message
news:<pxbmzx62nul.fsf@news.bourguet.org>...
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
c'est dans F::F() que tu crees l'alias en appellant B::B() avec deux
this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le UB:
struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
Ce code marchera (contraitement a ton exemple qui met bien les point
sur les 'i' ;-), mais je pense que la norme lui attribue quand meme
un UB, p etant un alias sur D* mais de type effectif A* au meme
titre que this...
Je crois que c'est bien defini.
§3.8 :
1 The lifetime of an object is a runtime property of the object. The
lifetime of an object of type T begins when:
-- storage with the proper alignment and size for type T is
obtained, and
-- if T is a class type with a non-trivial constructor, the
constructor call has completed.
[...]
5 Before the lifetime of an object has started but after the storage
which the object will occupy has been allocated [...], any pointer
that refers to the storage location where the object will be or was
located may be used but only in limited ways. [...] If the object
will be or was of a non-POD class type, the program has undefined
behavior if:
[...]
-- the pointer is implicitely converted to a pointer to a base
class type, or
[...]
Alors, dans le cas ci-dessus : 1) this est un D*, un pointeur à un objet
avec un type de classe non POD, et 2) l'appel du constructeur de A le
convertit implicitement en pointeur à une base du type. C'est donc un
comportement indéfini.
En fait, je me démande aussi... Indépendamment du paramètre, il faut
bien passer le this au constructeur de base. Est-ce que ça ne compte pas
comme conversion implicite en pointeur à une base aussi ? Si oui, je
dirais qu'on a bien affaire à un défaut dans la norme.
Dans la pratique, je n'ai jamais eu de problème qu'avec des classes de
base virtuelles. En revanche, quand j'ai essayé le suivant :
class MyIStream : private virtual MyStreambuf, public std::istream
...
MyIStream::MyIStream()
: std::istream( this )
{
}
avec au moins un compilateur, le pointeur passé à std::istream n'était
pas valid, c-à-d qu'il ne containait pas l'adresse de l'objet
std::streambuf classe de base de MyStreambuf.
En ôtant la dérivation virtuelle, ça marche partout. Mais le
comportement reste indéfini selon la norme. (Note que la seule chose que
fait std::istream avec le pointeur, c'est de le passer vers sa classe de
base, pour à la fin le stocker dans une variable membre de std::ios. Pas
que ce soit garanti par la norme, mais dans la pratique, c'est comme ça
que ça se passe.)
Jean-Marc Bourguet wrote in message
news:...Laurent Deniau writes:c'est dans F::F() que tu crees l'alias en appellant B::B() avec deux
this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le UB:struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};struct D : A {
D(): A(this) {} // alias
virtual void f();
};Ce code marchera (contraitement a ton exemple qui met bien les point
sur les 'i' ;-), mais je pense que la norme lui attribue quand meme
un UB, p etant un alias sur D* mais de type effectif A* au meme
titre que this...Je crois que c'est bien defini.
§3.8 :
1 The lifetime of an object is a runtime property of the object. The
lifetime of an object of type T begins when:
-- storage with the proper alignment and size for type T is
obtained, and
-- if T is a class type with a non-trivial constructor, the
constructor call has completed.
[...]
5 Before the lifetime of an object has started but after the storage
which the object will occupy has been allocated [...], any pointer
that refers to the storage location where the object will be or was
located may be used but only in limited ways. [...] If the object
will be or was of a non-POD class type, the program has undefined
behavior if:
[...]
-- the pointer is implicitely converted to a pointer to a base
class type, or
[...]
Alors, dans le cas ci-dessus : 1) this est un D*, un pointeur à un objet
avec un type de classe non POD, et 2) l'appel du constructeur de A le
convertit implicitement en pointeur à une base du type. C'est donc un
comportement indéfini.
En fait, je me démande aussi... Indépendamment du paramètre, il faut
bien passer le this au constructeur de base. Est-ce que ça ne compte pas
comme conversion implicite en pointeur à une base aussi ? Si oui, je
dirais qu'on a bien affaire à un défaut dans la norme.
Dans la pratique, je n'ai jamais eu de problème qu'avec des classes de
base virtuelles. En revanche, quand j'ai essayé le suivant :
class MyIStream : private virtual MyStreambuf, public std::istream
...
MyIStream::MyIStream()
: std::istream( this )
{
}
avec au moins un compilateur, le pointeur passé à std::istream n'était
pas valid, c-à-d qu'il ne containait pas l'adresse de l'objet
std::streambuf classe de base de MyStreambuf.
En ôtant la dérivation virtuelle, ça marche partout. Mais le
comportement reste indéfini selon la norme. (Note que la seule chose que
fait std::istream avec le pointeur, c'est de le passer vers sa classe de
base, pour à la fin le stocker dans une variable membre de std::ios. Pas
que ce soit garanti par la norme, mais dans la pratique, c'est comme ça
que ça se passe.)
Laurent Deniau writes:Jean-Marc Bourguet wrote:Laurent Deniau writes:c'est dans F::F() que tu crees l'alias en appellant B::B() avec
deux this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le
UB:
struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
Ce code marchera (contraitement a ton exemple qui met bien les
point sur les 'i' ;-), mais je pense que la norme lui attribue
quand meme un UB, p etant un alias sur D* mais de type effectif A*
au meme titre que this...
Je crois que c'est bien defini. C'est la partie que j'ai coupe de
l'exemple de la norme : le p dans A::A designe le sous-objet en
cours de construction
Juste, mon exemple etait trop simpliste, mais que penses-tu de:
struct D;
struct A {
A(D* p);
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
A::A(D* p) { p->f(); } // appelle A::f() au lieu de D::f()!
cette fois-ci l'alias est explicite mais le type effectif (et le
comportement) est le meme. UB or not UB?
Pour moi, p designe autre chose que le sous-objet en cours de
contruction, c'est donc un UB.
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
Jean-Marc Bourguet wrote:
Laurent Deniau <Laurent.Deniau@cern.ch> writes:
c'est dans F::F() que tu crees l'alias en appellant B::B() avec
deux this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le
UB:
struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
Ce code marchera (contraitement a ton exemple qui met bien les
point sur les 'i' ;-), mais je pense que la norme lui attribue
quand meme un UB, p etant un alias sur D* mais de type effectif A*
au meme titre que this...
Je crois que c'est bien defini. C'est la partie que j'ai coupe de
l'exemple de la norme : le p dans A::A designe le sous-objet en
cours de construction
Juste, mon exemple etait trop simpliste, mais que penses-tu de:
struct D;
struct A {
A(D* p);
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
A::A(D* p) { p->f(); } // appelle A::f() au lieu de D::f()!
cette fois-ci l'alias est explicite mais le type effectif (et le
comportement) est le meme. UB or not UB?
Pour moi, p designe autre chose que le sous-objet en cours de
contruction, c'est donc un UB.
Laurent Deniau writes:Jean-Marc Bourguet wrote:Laurent Deniau writes:c'est dans F::F() que tu crees l'alias en appellant B::B() avec
deux this avec deux types statiques differents mais le meme type
effectif. Donc p->f() invoque un B::f() qui n'exite pas. Bien vu,
ceci dit tu n'as pas besoin de l'heritage multiple pour avoir le
UB:
struct A {
A(A*p) { p->f(); } // invoque A::f(p), Ok mais pas voulu
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
Ce code marchera (contraitement a ton exemple qui met bien les
point sur les 'i' ;-), mais je pense que la norme lui attribue
quand meme un UB, p etant un alias sur D* mais de type effectif A*
au meme titre que this...
Je crois que c'est bien defini. C'est la partie que j'ai coupe de
l'exemple de la norme : le p dans A::A designe le sous-objet en
cours de construction
Juste, mon exemple etait trop simpliste, mais que penses-tu de:
struct D;
struct A {
A(D* p);
virtual void f();
};
struct D : A {
D(): A(this) {} // alias
virtual void f();
};
A::A(D* p) { p->f(); } // appelle A::f() au lieu de D::f()!
cette fois-ci l'alias est explicite mais le type effectif (et le
comportement) est le meme. UB or not UB?
Pour moi, p designe autre chose que le sous-objet en cours de
contruction, c'est donc un UB.
writes:Alors, avec quoi est-ce que tu proposes de la remplacer,
Les fonctions virtuelles pures sont des fonctions virtuelles comme les
autres sauf qu'on n'est pas oblige de les definir et qu'elles
empechent l'instanciation des classent qui en comportent.
C'est un comportement indefini si elles devraient etre executees mais
qu'elles n'ont pas ete definies. Ca me semble simple, pas de regles
particulieres, pas de changement bizarres dans la recherche quand on
passe de virtuel pur a non pur.
Le probleme qu'elles posent ne me semble pas plus complique pour les
editeurs de liens que celui des inline ou des templates.
kanze@gabi-soft.fr writes:
Alors, avec quoi est-ce que tu proposes de la remplacer,
Les fonctions virtuelles pures sont des fonctions virtuelles comme les
autres sauf qu'on n'est pas oblige de les definir et qu'elles
empechent l'instanciation des classent qui en comportent.
C'est un comportement indefini si elles devraient etre executees mais
qu'elles n'ont pas ete definies. Ca me semble simple, pas de regles
particulieres, pas de changement bizarres dans la recherche quand on
passe de virtuel pur a non pur.
Le probleme qu'elles posent ne me semble pas plus complique pour les
editeurs de liens que celui des inline ou des templates.
writes:Alors, avec quoi est-ce que tu proposes de la remplacer,
Les fonctions virtuelles pures sont des fonctions virtuelles comme les
autres sauf qu'on n'est pas oblige de les definir et qu'elles
empechent l'instanciation des classent qui en comportent.
C'est un comportement indefini si elles devraient etre executees mais
qu'elles n'ont pas ete definies. Ca me semble simple, pas de regles
particulieres, pas de changement bizarres dans la recherche quand on
passe de virtuel pur a non pur.
Le probleme qu'elles posent ne me semble pas plus complique pour les
editeurs de liens que celui des inline ou des templates.
Si l'intention est que D_A dérive de A (chose que je crois),
alors, le comportement est bien indéfini, selon §3.8/5, point 2.
Mais ça n'a pas grand chose à voir avec la discussion en cour (et à
mon avis, cette restriction représente un défaut dans la norme -- il
faut que le compilateur sache à cet instant comment convertir this
en D_A*, parce qu'il a dû le faire correctement déjà pour appeler le
constructeur de D_A).
Si l'intention est que D_A dérive de A (chose que je crois),
alors, le comportement est bien indéfini, selon §3.8/5, point 2.
Mais ça n'a pas grand chose à voir avec la discussion en cour (et à
mon avis, cette restriction représente un défaut dans la norme -- il
faut que le compilateur sache à cet instant comment convertir this
en D_A*, parce qu'il a dû le faire correctement déjà pour appeler le
constructeur de D_A).
Si l'intention est que D_A dérive de A (chose que je crois),
alors, le comportement est bien indéfini, selon §3.8/5, point 2.
Mais ça n'a pas grand chose à voir avec la discussion en cour (et à
mon avis, cette restriction représente un défaut dans la norme -- il
faut que le compilateur sache à cet instant comment convertir this
en D_A*, parce qu'il a dû le faire correctement déjà pour appeler le
constructeur de D_A).