C ++: ¿Cómo puedo evitar “inválido covariante tipo de retorno” en las clases heredadas sin poner?

StackOverflow https://stackoverflow.com/questions/2410532

  •  18-09-2019
  •  | 
  •  

Pregunta

Tengo una jerarquía de clases bastante complejo en el que las clases son en forma de cruz en función de uno al otro: Hay dos clases abstractas A y C que contiene un método que devuelve una instancia de C y A, respectivamente. En sus clases heredadas Quiero usar un tipo de co-variante, que es en este caso un problema, ya que no sé una forma de visión de declarar la nave de la relación de herencia.

Me obtener una "test.cpp: 22: error: no válido para el tipo de retorno covariantes 'virtual D * B :: OUTC ()'" - error ya que el compilador no sabe que D es una subclase de C

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

Si cambio el tipo de retorno de B :: OUTC () para C * el ejemplo compila. ¿Hay alguna manera de mantener y B * D * como tipo de retorno en las clases heredadas (que sería intuitivo para mí que hay una manera)?

¿Fue útil?

Solución

No conozco ningún camino de haber acoplado directamente a los miembros covariantes en C ++. Vas a tener ya sea para añadir una capa, o implementar covariante volver a sí mismo.

Para la primera opción

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class BI : public A {
public:
};

class D : public C {
public:
        BI* outA();
};

class B: public BI {
public:
        D* outC();
};

D* B::outC() {
        return new D();
}

BI* D::outA() {
        return new B();
}

y para el segundo

class C;

class A {
public:
        C* outC() { return do_outC(); }
        virtual C* do_outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
        virtual C* do_outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return static_cast<D*>(do_outC());
}

C* B::do_outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

Tenga en cuenta que esta segunda opción es lo que se hace implícitamente por el compilador (con algunas comprobaciones estáticas que el static_cast es válida).

Otros consejos

Por lo que yo sé, no hay manera de hacer esto sin conversión explícita. El problema es que la definición de la clase B no puede saber que D es una subclase de C hasta que ve una definición completa de D clase, pero la definición de D clase no puede saber que B es una subclase de A hasta que se ve una definición completa de B clase, y por lo que tienen una dependencia circular. Esto no se puede resolver con forward-declaraciones debido a que una declaración adelantada por desgracia no se puede especificar una relación de herencia.

Hay un problema similar con el intento de poner en práctica un método clone() covariante el uso de plantillas, lo que me pareció puede ser resuelto , pero la solución análoga sigue fallando aquí porque la referencia circular sigue siendo imposible de resolver.

No se puede hacer esto debido a las expectativas del cliente lado. Cuando se utiliza una instancia de C, no se puede saber qué tipo de C es (una D o algo más). Por lo tanto, si almacena el puntero B (como resultado de una llamada a la clase derivada, pero no se sabe que en tiempo de compilación) en una Un puntero, no estoy seguro de que todo el material de memoria será correcta.

Cuando se llama a un método en un tipo polimórfico, el entorno de ejecución tiene que comprobar el tipo dinámico del objeto y se mueve punteros para que se adapte a su jerarquía de clases. No estoy seguro de que usted debe depender de covarianza. Echar un vistazo a esta

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top