2010-03-09 12 views
10

[Todo lo siguiente se ensayó usando Visual Studio 2008 SP1]C++ vs. C++/CLI: calificación Const de función virtual Parámetros

En C++, calificación const de tipos de parámetros no afecta al tipo de una función (8.3.5/3: "Cualquier cv-calificador la modificación de un tipo de parámetro se elimina")

Así, por ejemplo, en la siguiente jerarquía de clases, Derived::Foo anulaciones Base::Foo:

struct Base 
{ 
    virtual void Foo(const int i) { } 
}; 

struct Derived : Base 
{ 
    virtual void Foo(int i) { } 
}; 

Considérese una jerarquía similar en C++/CLI:

ref class Base abstract 
{ 
public: 
    virtual void Foo(const int) = 0; 
}; 

ref class Derived : public Base 
{ 
public: 
    virtual void Foo(int i) override { } 
}; 

Si a continuación, crear una instancia de Derived:

int main(array<System::String ^> ^args) 
{ 
    Derived^ d = gcnew Derived; 
} 

se compila sin errores o advertencias. Cuando lo ejecuto, se lanza la siguiente excepción y luego termina:

An unhandled exception of type 'System.TypeLoadException' occurred in ClrVirtualTest.exe

Additional information: Method 'Foo' in type 'Derived'...does not have an implementation.

Esa excepción parece indicar que la calificación const del parámetro no afecta al tipo de la función en C++/CLI (o, por lo al menos afecta a la anulación de alguna manera). Sin embargo, si me comente la línea que contiene la definición de Derived::Foo, el compilador informa el siguiente error (en la línea en main donde se crea una instancia de la instancia de Derived):

error C2259: 'Derived': cannot instantiate abstract class

Si añado el calificador const a la parámetro de Derived::Foo o elimine el calificador const del parámetro Base::Foo, se compila y se ejecuta sin errores.

Creo que si la calificación const del parámetro afecta el tipo de la función, debería obtener este error si la calificación const del parámetro en la función virtual de clase derivada no coincide con la calificación const del parámetro en la función virtual de la clase base.

Si cambio el tipo de parámetro de un intDerived::Foo 's a una double, me sale el siguiente aviso (además del error antes mencionado, C2259):

warning C4490: 'override': incorrect use of override specifier; 'Derived::Foo' does not match a base ref class method

Por lo tanto, mi pregunta es, efectivamente, ¿la constificación de los parámetros de la función afecta el tipo de la función en C++/CLI? Si es así, ¿por qué compila esto y por qué no hay errores o advertencias? Si no, ¿por qué se lanza una excepción?

+0

Actualización: He informado de esto como un error en Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/540788 (he copiado el enlace aquí desde la discusión a continuación, ya que fue enterrado en la conversación) –

+0

Un miembro del equipo del compilador de Microsoft C++/CLI confirmó a partir del 21 de marzo que es un error y está explorando el impacto de una corrección en el código existente. –

+0

@Ben: Gracias. El defecto que presenté en Microsoft Connect se cerró hoy como "no se solucionará". "Hola: gracias por informar sobre este problema. Desafortunadamente, de acuerdo con nuestro análisis de la gravedad de este problema combinado con nuestros recursos limitados, no podremos solucionar este problema en la próxima versión de Visual C++". Oh, bueno :-) –

Respuesta

8

Bueno, es un error. Los modificadores const se emiten a los metadatos con el modificador personalizado modopt. Desafortunadamente, las reglas de lenguaje C++/CLI no coinciden con las reglas CLI. Capítulo 7.1.1 de la especificación CLI dice:

Custom modifiers, defined using modreq (“required modifier”) and modopt (“optional modifier”), are similar to custom attributes (§21) except that modifiers are part of a signature rather than being attached to adeclaration. Each modifer associates a type reference with an item in the signature.

The CLI itself shall treat required and optional modifiers in the same manner. Two signatures that differ only by the addition of a custom modifier (required or optional) shall not be considered to match. Custom modifiers have no other effect on the operation of the VES.

Así, el CLR dice que Derivado :: foo() no es una anulación, C++/CLI dice que es. El CLR gana.

Puede informar el error en connect.microsoft.com pero probablemente sea una pérdida de tiempo. Creo que esta incompatibilidad fue intencional. Deberían haber cambiado las reglas del lenguaje para C++/CLI pero seguramente pensaban que la compatibilidad con C++ era más importante.Los modificadores de CV son un dolor de todos modos, hay otros escenarios que no son bien compatibles, const indicadores para const para uno. Esto no se puede aplicar en tiempo de ejecución de todos modos, el CLR no tiene soporte para eso.

+0

Gracias. Había buscado en la especificación C++/CLI, pero no pensé en buscar en la especificación CLI. Al no haber usado mucho .NET, no sabía sobre el soporte limitado de la CLI para la calificación de const hasta que comencé a investigar este tema. Como seguimiento, ¿hay alguna razón por la que el compilador de C++/CLI no pueda simplemente omitir el modificador personalizado cuando genera el IL? –

+0

No puede, carga las definiciones de clase de los metadatos del conjunto. No archivos de encabezado Esas definiciones necesitan ser codificadas usando las capacidades de metadatos. Salir de los calificadores CV por completo sería demasiado incompatible. –

+0

Parece que obtendría un comportamiento diferente si solo # incluye el encabezado de la misma biblioteca que si llama a otra DLL ... Loco :( –

3

Es un error, y no es específico de C++/CLI.

https://connect.microsoft.com/VisualStudio/feedback/details/100917/argument-const-ness-is-part-of-member-function-type-signature

El hecho es, el compilador C++ se supone que quitarse de nivel superior const/volátil. Solo es importante la const/volátil en el tipo apuntado de un puntero o referencia. Si el compilador lo hizo correctamente, el CLR no tendrá voz en lo que está sucediendo.

Por cierto este es el IL generado por el compilador con/clr: pura

.class private abstract auto ansi beforefieldinit Base 
    extends [mscorlib]System.Object 
{ 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
     .maxstack 1 
     L_0000: ldarg.0 
     L_0001: call instance void [mscorlib]System.Object::.ctor() 
     L_0006: ret 
    } 

    .method public hidebysig newslot abstract virtual instance void Foo(int32 modopt([mscorlib]System.Runtime.CompilerServices.IsConst)) cil managed 
    { 
    } 

} 

.class private auto ansi beforefieldinit Derived 
    extends Base 
{ 
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 
    { 
     .maxstack 1 
     L_0000: ldarg.0 
     L_0001: call instance void Base::.ctor() 
     L_0006: ret 
    } 

    .method public hidebysig virtual instance void Foo(int32 i) cil managed 
    { 
     .maxstack 0 
     L_0000: ret 
    } 

} 

Esto definitivamente viola la regla James aparece en relación con la eliminación de la fase de clasificación de nivel superior.

secciones más relevantes de la especificación C++/CLI:

8.8.10.1 Function overriding

[snip]

  1. A derived class function explicitly overrides a base class virtual function having the same name, parameter-type-list, and cv-qualification, by using the function modifier override, with the program being ill-formed if no such base class virtual function exists

12.3 Declarator types

The C++ Standard (§8.3.5/3) is augmented, as follows:
The resulting list of transformed parameter types and the presence or absence of the ellipsis is the function’s parameter-type-list.

Así que me lleva a creer que la regla sobre la supresión de la CV-calificadores se aplica a C++/CLI, así, debido a que la especificación se pide expresamente a cabo sección 8.3.5/3 de la Norma ISO C++.

+0

Para código nativo, ese error ha sido reparado, al menos a partir de VS2008 SP1 (el compilador incluso da una advertencia, C4373, "las versiones anteriores del compilador no anulaban cuando los parámetros solo diferían por calificadores const/volátiles"). Solo puedo reproducir el problema mencionado en la publicación original con tipos de CLI (es decir, tipos 'ref class'). –

+0

@James, estoy de acuerdo en que mi código de reproducción finalmente no causa problemas con VS2008 SP1 (la primera solución no lo solucionó). Y puedo reproducir tu problema, ya que enumeró un error en Connect lo validaré. –

Cuestiones relacionadas