2012-05-07 19 views
6

¿El siguiente estándar está conforme? ¿Puedes citar la sección?¿Una función virtual anula una función no virtual del mismo nombre en una clase base?

struct A 
{ 
    virtual void func() = 0; 
}; 

struct B 
{ 
    void func(){} 
}; 

struct C : public A, public B 
{ 
    virtual void func(){ B::func(); } 
}; 

Estoy recibiendo una advertencia del compilador extraña en VS2010 en el código equivalente pero más complicado que apunta a la declaración func 's en la más derivado de la clase: warning C4505: unreferenced local function has been removed. No tengo idea de por qué el compilador cree que una función virtual declarada en una clase es local; sin embargo, no puedo reproducir esa advertencia en un ejemplo más simple.

Editar:

me di cuenta de una pequeña caja repro por el aviso. Creo que estaba tomando el camino equivocado suponiendo que estaba relacionado con el ocultamiento de funciones. Aquí está el caso de repro:

template<typename T> 
struct C 
{ 
    int GetType() const; 
    virtual int func() const; // {return 4;} // Doing this inline removes the warning <-------------- 
}; 

template<typename T> 
int C<T>::GetType() const 
{ 
    return 0; 
} 

template<> 
int C<int>::GetType() const 
{ 
    return 12; 
} 

template<typename T> 
int C<T>::func() const 
{ 
    return 3; 
} 

// Adding the following removes the warning <-------------------- 
// template<> 
// int C<int>::func() const 
// { 
//  return 4; 
// } 

Estoy bastante seguro de que esto es solo un error VS2010.

+4

"en código equivalente pero más complicado ... no se puede reproducir esa advertencia en un ejemplo más simple". Entonces probablemente no sean equivalentes. –

+0

El código anterior no produce la advertencia de la que hablas en VS2010. No hay nada semánticamente mal con eso, pero la elección del diseño es extraña para mí. – AJG85

+0

Todavía estoy tratando de encontrar la manera de reprogramar esa advertencia: voy a editar cuándo y si lo hago. – David

Respuesta

3

El código está bien formado. C::func reemplaza A::func. B::func es una función no relacionada. La especificación lee (10.3/2):

Si una función miembro virtual vf se declara en una clase de Base y en una clase de Derived, derivada directa o indirectamente de Base, una función miembro vf con el mismo nombre, el parámetro -type-list, cv-qualification y ref-qualifier (o la ausencia de la misma) como Base::vf se declara, entonces Derived::vf también es virtual (esté o no declarado) e invalida111 Base::vf.

C::func tiene el mismo nombre que A::func y A::func es virtual, por lo tanto C::func anulaciones A::func. B::func no tiene relación con A::func; No sé si hay algún lenguaje en la especificación que aborde expresamente ese escenario.

El compilador Beta de Visual C++ 11 no emite ninguna advertencia o error para este código.

0

Let me google it for you.

function: función local no referenciado se ha eliminado

la función dada es local y no se hace referencia en el cuerpo del módulo; por lo tanto, la función es código muerto.

El compilador no generó código para esta función muerta.

El compilador determinó estáticamente que la función no se usó, por lo que no generó código para esa función y le advierte que tiene un código inútil. Un poco más complicado que el variable no utilizada habitual advertencia, pero sobre el mismo efecto: huele a código muerto.

+1

Lo hice google, gracias. Esto tiene sentido para la función 'LOCAL' solamente. Ni siquiera puedo ver cómo el compilador sabría si una función no se utiliza, tendría que ser el enlazador, en cuyo caso sería una advertencia del enlazador. ¿Alguna vez has visto una advertencia sobre una función virtual no utilizada en una clase? ¿NUNCA? – David

+0

@Dave: la función se declara (implícitamente) 'inline', lo que significa que si cualquier otra unidad de compilación lo usara, debería aparecer en esa otra unidad de compilación. Entonces el compilador no tiene que preocuparse por las referencias externas a la función, puede tratarla como local. –

+0

Ahhh. Interesante. Pero, pero es virtual, ¿puede realmente resolverse si se llama o no en ese nivel? Y, de hecho, me estoy volviendo a mi postura anterior: ¿Has visto esta advertencia en tu propio código para, digamos, una clase de plantilla con un acceso o mutador que no se llama y está en línea ya que está en una clase de plantilla? Ese es el mismo caso, ¿verdad? – David

1

Normalmente, las funciones virtuales no pueden eliminarse por el vinculador como código muerto, porque sus direcciones deben aparecer en el vtable.Sin embargo, si se determinó que el vtable para struct C era un código muerto (lo que podría suceder si todos los constructores también son código muerto), también se puede eliminar esa última referencia restante.

Como la función está declarada inline, esta optimización de eliminación de código inactivo no tiene que esperar hasta el tiempo del enlace; puede ser hecho por el compilador. dice la norma (véase la sección 7.1.2):

una función en línea se definirá en cada unidad de traducción en el que es utilizado ODR- y deberá tener exactamente la misma definición en todos los casos (3,2). [Nota: se puede encontrar una llamada a la función en línea antes de que su definición aparezca en la unidad de traducción. - nota final] Si la definición de una función aparece en una unidad de traducción antes de su primera declaración como en línea, el programa está mal formado. Si una función con enlace externo es declarada en línea en una unidad de traducción, se declarará en línea en todas las unidades de traducción en las que aparece; no se requiere diagnóstico. Una función inline con enlace externo debe tener la misma dirección en todas las unidades de traducción. Una variable local static en una función extern inline siempre se refiere al mismo objeto. Un literal de cadena en el cuerpo de una función extern inline es el mismo objeto en diferentes unidades de traducción. [Nota: un literal de cadena que aparece en un argumento predeterminado no está en el cuerpo de una función en línea simplemente porque la expresión se usa en una llamada de función de esa función en línea. - nota final] Un tipo definido dentro del cuerpo de una función extern inline es del mismo tipo en cada unidad de traducción.

Si el compilador puede determinar la función nunca se utiliza en esta unidad de traducción , se sabe que ninguna unidad de traducción que hace uso de la función debe contener su propia definición idéntica, y generará el código. Por lo tanto, puede omitir la generación de código como si no tuviera enlaces externos en absoluto.

Generar una advertencia es completamente inútil, sin embargo, ya que habrá una gran cantidad de falsos positivos (cuando la función inline se utiliza odr y se genera código en alguna otra unidad de compilación).

Cuestiones relacionadas