2010-09-21 18 views
5

¿por qué si tenemos un operador de asignación virtual puro en una clase base, implementamos ese operador en la clase derivada, se da un error de enlazador en la clase base?C++: operador de asignación virtual puro

actualmente sólo tengo la siguiente explicación sobre http://support.microsoft.com/kb/130486, dijo que el comportamiento es por diseño ya las reglas de herencia normales no se aplica.

no está claro para mí, ¿por qué generar error de engarce de diseño? ¿Puede alguien darme una explicación más clara sobre esto?

edición: añadido mi código simplificado de los cuales se produjo el error:

class __declspec(dllexport) BaseClass { 
public: 
    int memberA; 
    virtual BaseClass& operator=(const BaseClass& rhs) = 0; 
}; 

class __declspec(dllexport) DerivedClass : public BaseClass { 
public: 
    int memberB; 
    DerivedClass():memberB(0) {} 
    virtual BaseClass& operator=(const BaseClass& rhs) { 
     this->memberA = rhs.memberA; 
     this->memberB = 1; 
     return *this; 
    } 
}; 

int main(void) 
{ 
    DerivedClass d1; 
    DerivedClass d2; 

    BaseClass* bd1 = &d1; 
    BaseClass* bd2 = &d2; 

    *bd1 = *bd2; 
} 

el código compilará sin errores sin__declspec(dllexport) y/o sin operador virtual pura = declaración sobre la clase base .

sin __declspec(dllexport) después de la asignación de *bd1 = *bd2;, D1 :: memberB es 1, pero con __declspec(dllexport) D1 :: memberB se deja sin cambios

con __declspec(dllexport), y sin declaración virtual pura, después de la asignación de *bd1 = *bd2;, D1 :: memberB se deja sin cambios

+2

podría ser útil para publicar un código de ejemplo junto con el error del enlazador completo MSVC escupió – Necrolis

+0

FWIW, el artículo 33 del _More Effective C++ _ de Scott Meyers ("Hacer clases no hoja resumen") cubre cómo tratar con operator = en una jerarquía de herencia. –

+0

@necrolis: el código de ejemplo está en el enlace indicado arriba – uray

Respuesta

7

De la sección 12.8 de la norma:

13 El operador de asignación de copias implícitamente definido para la clase X realiza la asignación de sus objetos independientes en forma de miembro. Las clases base directas X de se asignan primero, en el orden de su declaración en la base-especificador-list, y luego se asignan los datos de datos no-estáticos de X, en el orden en el que fueron declarados en la definición de clase.Cada subobjeto se asigna de la manera apropiada a su tipo:

- si el subobjeto es de tipo de clase, se utiliza el operador de asignación de copia para la clase (como por calificación explícita; que es, ignorando cualquier posible virtual reemplazando funciones en más clases derivadas);

La subclase está utilizando el operador de asignación de copia definido implícitamente, y no existe una definición del operador de asignación de copia de la clase base, pero se declara, por lo que se obtiene un error de enlace en lugar de un error de compilación.

+0

Creo que está hablando de operator =, no del constructor de copias. Para el controlador de copia, virtual y puro virtual debería ser un error de compilación inmediato, ya que realmente no tiene sentido para ellos. –

+2

Su enlace es sobre operador = y de eso se trata mi publicación. –

+0

Desde el OP 'entonces implementamos ese operador en la clase derivada' Voy a decir que tiene un operador de asignación de copia explícito en el niño (no implícito que su respuesta cubriría correctamente), y ninguna indicación de que sea o no está llamando a la asignación de copia primaria (pura virtual). –

7

operador = no heredado. Su código no tiene sentido en C++, por lo que los compiladores pueden emitir cualquier error que deseen.

Desde el artículo de KB que apuntaban a: http://support.microsoft.com/kb/130486

Desde operador = no se hereda, cualquier declaración del operador = en la clase base no se utiliza e innecesario. No declare el operador = en la clase base.

Probablemente sea solo un efecto secundario de cómo se compilan, y simplemente le informan que no lo consideran un error, por lo que no hay necesidad de solucionarlo. "Por diseño" no necesariamente significa que decidieron específicamente que este error del vinculador es el mensaje de error correcto para esta situación: el código es incorrecto, se obtiene un error, por lo que desde su punto de vista, están hecho.

+0

¿De dónde es esa cita? –

+0

El artículo KB de OP. Voy a udpate –

+0

+1 para la cotización – bjskishore123

2

En el código de ejemplo:

class A 
{ 
public : 
    // To workaround LNK2001, comment the following line. 
    virtual const A& operator=(const A& f) = 0; 
}; 

class B : public A 
{ 
public : 
    const A& operator=(const A& g) {return g;} 
}; 

B aB1, aB2; 

int /*void*/ main(void) 
{ 
    aB2 = aB1; 
} 

la línea aB2 = aB1 no llama const A& B::operator=(const A&), pero llama a la vez suministrado B& operator=(const B&); que a su vez utiliza el operador de asignación para asignar la parte de base de la clase de forma automática. Pero cuando se trata de vincular, resulta que eso nunca se implementó.

+1

Se ha anulado el operador de asignación. Al igual que declarar cualquier constructor (no plantilla), efectivamente se desactiva el constructor predeterminado y el constructor de copia definidos implícitamente, declarando cualquier 'operador =' (no plantilla) desactivar el operador de asignación implícitamente definido. –

+0

@ Matthieu: ¿Eso califica como * copia de asignación *? Y después de todo, 'struct X {X & operator = (int);};' no me impide asignar una X a otra que debería, si * cualquier * sobrecarga de 'operator =' deshabilitó la predeterminada. - Del mismo modo, cualquier constructor no desactiva el constructor de copia, solo un constructor de copia válido definido por el usuario. – UncleBens

+0

tiene razón, pero cuando se usa 'B & operator = (A const &)' se llama esta versión en lugar de la predeterminada (al menos con VC++ 10) ... ahora estoy confundido y es demasiado tarde para mí para ver esto ... –

Cuestiones relacionadas