Domanda

Oppure, ci sono altri effetti negativi noti nell'impiego di __declspec (novtable)? Non riesco a trovare riferimenti a problemi.

È stato utile?

Soluzione

MSCV utilizza un vptr per oggetto e un vtbl per classe per implementare meccanismi OO come RTTI e funzioni virtuali.
Quindi RTTI e le funzioni virtuali funzioneranno bene se e solo se vptr è stato impostato correttamente.

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 dovrebbe essere una classe astratta quando si utilizza __declspec (novtable) .
Non ci sarà istanza di B se non nel costruttore di D1.
E __declspec (novtable) non ha effetti negativi nella maggior parte dei casi.

Ma durante la costruzione della classe derivata __declspec (novtable) la renderà diversa dalla semantica 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.
    }
};

Nota: virtual f () = 0 ; rende f una pura funzione virtuale e B una classe astratta.
La definizione di una pura funzione virtuale potrebbe (non deve ) mancante.
C ++ consente la chiamata di funzione virtuale nel costruttore che non è consigliabile.

Aggiornamento: Un errore in D2: il vptr nel costruttore derivato.

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
};

Ma vptr è indeterminato durante la costruzione. È uno dei motivi per cui la chiamata di funzione virtuale nel costruttore non è consigliata.

Se vptr in D2 :: D2 () era B e mancava la definizione di B :: f (), this- > f (); andrà in crash quando il puntatore alla funzione dereference nel vtbl.
Se vptr in D2 :: D2 () era B e B usa novtable, this- > f (); andrà in crash quando si verifica un vptr non inizializzato

In effetti, vptr in D2 :: D2 () è D2 in MSVC (msvc8). Il compilatore ha impostato vptr su D2 prima di eseguire altri codici in D2 :: D2 ().
Quindi this- > f (); chiama D2 :: f () e le tre asserzioni saranno violate.

Altri suggerimenti

se lo capisco correttamente: Qualsiasi chiamata fn virtuale all'interno di un ctor o di un dtor viene convertita in un collegamento in fase di compilazione. Non possiamo effettuare chiamate fn virtuali dai tori (c / d). Il motivo è che al momento in cui l'oggetto della classe base viene creato non ha conoscenza della classe derivata e quindi non può effettuare la chiamata alla classe derivata e quindi i dottori applicano la stessa logica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top