c++ - sirve - qué tienen en común una interfaz y una clase abstract
¿El uso de__declspec(novtable) en clases base abstractas afecta a RTTI de alguna manera? (2)
MSCV utiliza one vptr per object and one vtbl per class
para implementar el mecanismo OO, como RTTI y funciones virtuales.
Así que RTTI y las funciones virtuales funcionarán bien si y solo si el vptr se ha configurado correctamente.
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 debe ser una clase abstracta cuando use __declspec(novtable)
.
No habrá instancia de B excepto en el constructor de D1.
Y __declspec (novtable) no tiene efectos negativos en la mayoría de los casos.
Pero durante la construcción de la clase derivada __declspec(novtable)
diferenciará de la semántica de 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
; hace que f sea una pure virtual function
y B una clase abstracta.
La definition
de una función virtual pura could
(no must
) faltar.
C ++ permite llamadas de funciones virtuales en el constructor que no recomendamos.
Actualización: un error en D2: el vptr en el constructor derivado.
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
};
Pero vptr es indeterminado durante la construcción. Es una de las razones por las que no se recomiendan las llamadas a funciones virtuales en el constructor.
Si vptr en D2 :: D2 () era B y faltaba la definición de B :: f (), this->f();
se bloqueará cuando el puntero-a-función de desreferencia en el vtbl.
Si vptr en D2 :: D2 () era B y B usa novtable, this->f();
se bloqueará cuando se elimine la referencia de un vptr no inicializado.
De hecho, vptr en D2 :: D2 () es D2 en MSVC (msvc8). El compilador establece vptr a D2 antes de ejecutar otro código en D2 :: D2 ().
Entonces this->f();
llama a D2 :: f () y se violarán las tres afirmaciones.
O bien, ¿hay algún otro efecto negativo conocido al emplear __declspec (novtable)? Parece que no puedo encontrar referencias a ningún problema.
si lo entiendo correctamente: cualquier llamada fn virtual dentro de un ctor o un dtor se convierte en un enlace de tiempo de compilación. No podemos hacer llamadas fn virtuales desde (c / d) tors. La razón es que en el momento en que se crea el objeto de la clase base, no tiene conocimiento de la clase derivada y, por lo tanto, no puede realizar la llamada a la clase derivada y, a los dtors, se aplica la misma lógica.