2012-07-13 20 views
6

tengo una clase (vamos a llamarlo base por el momento) que tiene una interfaz protegida, incluyendo constructores protegidas etc. Algunas funciones de base devolver una instancia de base por valor:tema visibilidad para constructor de copia de clase base

class base { 
protected: 
    base() {} 
    base (base const &other) {} // line 6 
    base foo() { 
     base ret; 
     return ret; 
    } 
}; 

Estas funciones están envueltos en las clases derivadas para devolver el tipo derivado de este modo:

class derived : public base { 
private: 
    derived(base const &b) : base(b) {} 
public: 
    derived() : base() {} 
    derived foo() { 
     derived d(base::foo()); // line 21 
     return d; 
    } 
}; 

para facilitar la conversión del tipo base retorno en un derived tipo de devolución, proporciono un constructor privado en derived que maneja esto.

la compilación de este en Centos 5.8 con gcc 4.1.2 produce el siguiente error:

test.cpp: In member function ‘derived derived::foo()’: 
test.cpp:6: error: ‘base::base(const base&)’ is protected 
test.cpp:21: error: within this context 

con GCC 4.6.1 y 2.9 sonido metálico en Linux Mint 12, el código se compila archivos, incluso con -Wall -Wextra, además de una advertencia unused parameter para el constructor de copia base.

Creo que esto podría ser un error del compilador en gcc 4.1.2, pero no he podido encontrar nada en la red. ¿Alguien ha visto esto antes?

No puedo actualizar el compilador sin mucho dolor. ¿Hay alguna solución alternativa aparte de hacer público el constructor de copia de la clase base?


EDITAR I añadió base b; antes de la línea 21 en derived::foo(). En ese caso, gcc 4.6.1 y gcc 4.1.2 se quejan de que el ctor predeterminado de base está protegido, clang 2.9 compila sin previo aviso. Esto es lo que David Rodríguez - dribeas dijo en su comentario - no se puede llamar al ctor por defecto en una instancia diferente de base.


EDIT 2 El párrafo estándar que parece aplicarse aquí es 11.5 [class.protected]. gcc 4.1.2 parece ser correcto al rechazar mi código como incorrecto y me pregunto por qué gcc 4.6.1 y clang lo permiten. Ver mi propia respuesta para una solución preliminar.

+0

Dado que MarkB ha eliminado su respuesta, publicaré aquí el punto principal: 'protected' no da a los tipos derivados acceso a esos miembros en * cualquier * instancia de la base tipo. Solo puede acceder a los miembros protegidos de su propio tipo derivado. Es decir.'derived :: foo()' solo puede acceder a los miembros protegidos de 'base' de' this' o de cualquier otro objeto 'derived' (incluidos los objetos cuyo tipo completo se deriva de' derived') –

+0

Sí, he leído sobre eso también (incluso lo busqué en el estándar), y esta también fue mi primera idea, pero me pregunto por qué tanto gcc 4.6.1 como clang 2.9. compilar esto sin problemas. – arne

+0

+1 @ DavidRodríguez-dribeas ojo abierto. He estado bajo la impresión equivocada todo este tiempo. No solo eso, estaba ** seguro ** de exactamente lo contrario. –

Respuesta

0

Mi primera solución es hacer base 's copia ctor public. Para no permitir la copia de instancias derived utilizando el copiador de base, la herencia debe ser protected en lugar de public. Las clases resultantes ahora se ven así:

class base { 
protected: 
    base() {} 
public: 
    base (base const &other) {} 
protected: 
    base foo() { 
     base ret; 
     return ret; 
    } 
}; 

class derived : protected base { 
private: 
    derived(base const &b) : base(b) {} 
public: 
    derived() : base() {} 
    derived foo() { 
     derived d(base::foo()); 
     return d; 
    } 
}; 
1

Una solución que podría intentar implicaría la creación de un constructor privado para los derivados que construye su base llamando a la función de base:

class derived : base { 
    struct from_base_foo {}; 
    derived(from_base_foo) : base(base::foo()) {} 
public; 
    derived foo() { 
     return derived(from_base_foo()); 
    } 
}; 
+0

Probado, el error se emite para la llamada al constructor '' base'' en su nuevo ' 'derived'' constructor. – arne

+0

Oh, a la derecha se está quejando en la lista de inicialización al intentar vincular el rvalue 'base :: foo' al const lvalue pasado como argumento al constructor de copia' base' ... –

Cuestiones relacionadas