Question

Ou, existe-t-il d'autres effets négatifs connus de l'utilisation de __declspec (novtable)? Je n'arrive pas à trouver des références à des problèmes.

Était-ce utile?

La solution

MSCV utilise un vptr par objet et un vtbl par classe pour implémenter un mécanisme OO tel que RTTI et des fonctions virtuelles.
Ainsi, RTTI et les fonctions virtuelles fonctionneront correctement si et seulement si le vptr a été configuré correctement.

struct __declspec(novtable) B {
    virtual void f() = 0;
};
struct D1 : B {
    D1() {
    }       // after the construction of D1, vptr will be set to vtbl of D1.
};
D1 d1;      // after d has been fully constructed, vptr is correct.
B& b = d1;  // so virtual functions and RTTI will work.
b.f();      // calls D1::f();
assert( dynamic_cast<D1*>(&b) );
assert( typeid(b) == typeid(D1) );

B doit être une classe abstraite lorsque vous utilisez __ declspec (novtable) .
Il n'y aura pas d'instance de B sauf dans le constructeur de D1.
Et __declspec (novtable) n’a pas d’effet négatif dans la plupart des cas.

Mais lors de la construction de la classe dérivée __ declspec (novtable) , elle sera différente de la sémantique ISO C ++.

struct D2 : B {


    D2() {  // when enter the constructor of D2 \  
            //     the vtpr must be set to vptr of B \
            //     if  B didn't use __declspec(novtable).
            // virtual functions and RTTI will also work.

            this->f(); // should calls B::f();
            assert( typeid(*this) == typeid(B) );
            assert( !dynamic_cast<D2*>(this) );
            assert( dynamic_cast<B*>(this) );

            // but __declspec(novtable) will stop the compiler \
            //    from generating code to initialize the vptr.
            // so the code above will crash because of uninitialized vptr.
    }
};

Remarque: virtual f () = 0 ; fait de f une fonction virtuelle pure et B une classe abstraite.
La définition d'une fonction virtuelle pure pourrait (et non doit ) être manquante.
C ++ autorise l'appel de fonction virtuelle dans le constructeur, ce que nous ne recommandons pas.

Mise à jour: Une erreur dans D2: le vptr dans le constructeur dérivé.

struct D3 : B {  // ISO C++ semantic
    D3() {       // vptr must be set to vtbl of B before enter
    }            // vptr must be set to vtbl of D2 after leave
};

Mais vptr est indéterminé pendant la construction. C'est l'une des raisons pour lesquelles l'appel de fonction virtuelle dans le constructeur n'est pas recommandé.

Si vptr dans D2 :: D2 () était B et que la définition de B :: f () était manquante, this- > f (); se planterait lors de la déréférence du pointeur sur la fonction. dans le vtbl.
Si vptr dans D2 :: D2 () était B et B, utilisez novtable, this- > f (); plantera lorsque déréférencera un vptr non initialisé.

En fait, vptr dans D2 :: D2 () est D2 dans MSVC (msvc8). Le compilateur définit vptr sur D2 avant d'exécuter un autre code dans D2 :: D2 ().
Donc this- > f (); appelle D2 :: f () et les trois assertions seront violées.

Autres conseils

si je le comprends bien: Tout appel fn virtuel dans un ctor ou un dtor est converti en une liaison au moment de la compilation. Nous ne pouvons pas faire d’appels fn virtuels à partir des (c / d) torseurs. La raison en est qu’au moment de la création de l’objet de la classe de base, celui-ci n’a aucune connaissance de la classe dérivée et ne peut donc pas appeler la classe dérivée ni les attributs de la même logique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top