2012-09-26 23 views
6

Así que tengo una clase base abstracta sin métodos abstractos. Con el fin de hacer cumplir la abstracción, he declarado el destructor (no trivial) como virtual pura:Herencia virtual pura, herencia múltiple, y C4505

class AbstractClass 
{ 
public: 
    AbstractClass() 
    { 
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl; 
    } 
    virtual ~AbstractClass() = 0 
    { 
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl; 
    } 
}; 

class ConcreteClass : public AbstractClass 
{ 
public: 
    ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl; 
    } 
    virtual ~ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl; 
    } 
}; 

Esto construye y funciona como se esperaba; la salida de un bloque de código que simplemente define una instancia de ConcreteClass es

 

    AbstractClass::AbstractClass() 
    ConcreteClass::ConcreteClass() 
    ConcreteClass::~ConcreteClass() 
    AbstractClass::~AbstractClass() 

Ahora, cuando tengo derivar AbstractClass de otra clase se utiliza como una clase de interfaz, sí que tiene un (trivial) destructor virtual (puro o de otra manera) , aún funciona:

class IAlpha 
{ 
public: 
    virtual ~IAlpha() = 0 {} 
}; 

class AbstractClass : public IAlpha 
{ 
public: 
    AbstractClass() 
    { 
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl; 
    } 
    virtual ~AbstractClass() = 0 
    { 
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl; 
    } 
}; 

class ConcreteClass : public AbstractClass 
{ 
public: 
    ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl; 
    } 
    virtual ~ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl; 
    } 
}; 

El problema surge cuando intento de implementar dos interfaces diferentes de esta manera:

class IAlpha 
{ 
public: 
    virtual ~IAlpha() = 0 {} 
}; 

class IBeta 
{ 
public: 
    virtual ~IBeta() = 0 {} 
}; 

class AbstractClass : public IAlpha, public IBeta 
{ 
public: 
    AbstractClass() 
    { 
    std::wcout << L"AbstractClass::AbstractClass()" << std::endl; 
    } 
    virtual ~AbstractClass() = 0 
    { 
    std::wcout << L"AbstractClass::~AbstractClass()" << std::endl; 
    } 
}; 

class ConcreteClass : public AbstractClass 
{ 
public: 
    ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::ConcreteClass()" << std::endl; 
    } 
    virtual ~ConcreteClass() 
    { 
    std::wcout << L"ConcreteClass::~ConcreteClass()" << std::endl; 
    } 
}; 

en este punto, cuando bu ilding, recibo el siguiente mensaje de advertencia:

warning C4505: 'AbstractClass::~AbstractClass' : 
unreferenced local function has been removed

Curiosamente, sin embargo, la salida sigue mostrando AbstractClass::~AbstractClass() recibiendo llamadas.

¿Esto es un error en MSVC9 (VS 2008)? ¿Puedo ignorar esta advertencia?

Editar: He intentado separar las definiciones de métodos virtuales puros de la definición de clase también, ya que aparentemente la sintaxis = 0 {} no es realmente válida. Desafortunadamente, C4505 todavía aparece, si especifico inline o no.

Como no he encontrado ninguna forma de #pragma de advertir estos métodos (la advertencia se dispara desde otras partes del código), es posible que tenga que eliminar el especificador virtual puro de AbstractClass y confiar en que los constructores protegido. No es una solución ideal, pero es mejor que reescribir la jerarquía de clases para evitar una advertencia errónea.

Respuesta

0

¿Intentó definir los destructores de una manera no en línea? Tal vez la advertencia está relacionada con eso.

Tales como this code.

+0

He intentado el código en su enlace; recibe la misma advertencia aunque, como antes, funciona correctamente cuando se ejecuta. – somethingdotjunk

0

El código no debe compilarse. Las funciones virtuales puras no se pueden definir dentro de la definición de la clase. Mueva la definición fuera de las clases:

struct IAlpha { 
    virtual ~IAlpha() = 0; 
}; 
inline IAlpha::~IAlpha() {} 
// similarly for the rest. 

Además de eso, el código es correcto y debe compilarse.

+0

Interesante; No sabía que no se podía combinar el especificador virtual puro y el cuerpo del método. Desafortunadamente, lo intenté de esta manera también y la advertencia aún aparece (ver respuesta de jeffmagill). – somethingdotjunk

3

Este es un error en MSVC++ 2010 y anteriores. El código en realidad obtiene llamado a pesar de que el compilador afirma haber eliminado el código. Parece ser fijado en MSVC++ 2012. Otros compiladores como gcc o clang no emiten una advertencia. La sintaxis "... = 0 {...}" es ilegal según la sección estándar 10.4 de C++ 03.2 (a pesar de que MSVC++ no se queja), como ya se ha señalado:

Nota: una declaración de función no puede proporcionar tanto una pura especificador y una definición

Sin embargo, la definición de una pura el destructor virtual en general no es ilegal y la sección 12.4.7 indica:

Un destructor puede declararse virtual (10.3) o puro virtual (10.4); si se crean cualquier objeto de esa clase o cualquier clase derivada en el programa , se definirá el destructor. Si una clase tiene una clase base con un destructor virtual, su destructor (ya sea el usuario declarado implícitamente) es virtual.

Mi manera de desactivar la advertencia es añadir las siguientes líneas al encabezado:

#if defined(_MSC_VER) && (_MSC_VER <= 1600) 
# pragma warning(disable:4505) 
#endif 

Si desea desactivar las advertencias de forma más local entonces #pragma warning(push) y #pragma warning(pop) podría ser de ayuda. Ver http://msdn.microsoft.com/en-us/library/2c8f766e(v=vs.80).aspx

Dado que el código parece ser llamado puede ignorar las advertencias en mi opinión.

+0

Me interesaría saber de dónde se informó este error, así que puedo citarlo. – chappjc

0

No se puede definir la función virtual en línea.

Porque el en línea está en compilación. Lo virtual está en tiempo de ejecución.