Dada esta artificial ejemplo:C++ miembro-función de encadenamiento de tipos de retorno y las clases derivadas
struct point_2d {
point_2d& x(int n) {
x_ = n;
return *this;
}
point_2d& y(int n) {
y_ = n;
return *this;
}
int x_, y_;
};
struct point_3d : point_2d {
point_3d& z(int n) {
z_ = n;
return *this;
}
int z_;
};
int main() {
point_3d p;
p.x(0).y(0).z(0); // error: "point_2d" has no member named "z"
return 0;
}
la idea es utilizar "encadenamiento-función miembro" para ser capaz de llamar a más de una función miembro en una fila . (Hay muchos ejemplos de esto; el anterior es el más corto que pude pensar para hacer esta pregunta. Mi problema real es similar y se describe a continuación.)
El problema es que si una clase derivada se agrega su propio encadenamiento de funciones-miembros, pero usted llama primero a la función miembro de la clase base, obtiene una referencia de clase base que, por supuesto, no funcionará para llamar a la función miembro de una clase derivada.
¿Hay alguna forma inteligente de resolver este problema y aún así mantener la capacidad de realizar un encadenamiento de función de miembro?
el problema real
Mi real problema es que mi clase base es una excepción y mi clase derivada es una clase derivada de la excepción de base. Para aquellas clases también, quiero usar funciones miembro de encadenamiento:
class base_exception : public std::exception {
// ...
base_exception& set_something(int some_param) {
// ...
return *this;
}
};
class derived_exception : public base_exception {
// ...
};
int main() {
try {
// ...
if (disaster)
throw derived_exception(required_arg1, required_arg2)
.set_something(optional_param);
}
catch (derived_exception const &e) {
// terminate called after throwing an instance of 'base_exception'
}
}
El problema es que set_something()
vuelve base_exception
pero el catch
espera un derived_exception
. Por supuesto, un humano puede decir que el tipo real de la excepción es un derived_exception
pero aparentemente el compilador no sabe.
Ese es el problema que realmente estoy tratando de resolver, es decir, cómo tener una clase de excepción base para poder establecer parámetros opcionales en el objeto de excepción pero devolver una instancia del tipo derivado. El ejemplo point_2d
que di más arriba es (creo) una versión más pequeña y simple del mismo problema para que las personas entiendan y que una solución al problema más pequeño también resolverá mi problema real.
en cuenta que yo tenía intención de hacerla base_exception
una plantilla y pase en el tipo derivado como:
template<class Derived>
class base_exception {
// ...
Derived& set_something(int some_param) {
// ...
return *this;
}
};
Creo que en realidad no resuelve el problema, pero no es una solución perfecta porque si otra clase more_derived_exception
deriva desde derived_exception
, entonces volvemos al mismo problema.
El 'base_exception' idea que tenga al final de su pregunta que se conoce como el patrón de plantilla Curiosamente Recurrente (CRTP). No creo que proporcione una solución en su caso, ya que no podrá tener una sola clase base raíz para su jerarquía de excepciones. –
@Emile: Sí, dije que no es una solución perfecta y por qué. –
Simplemente estaba señalando, para beneficio de otros lectores, que el patrón que ha mostrado tiene un nombre particular. También le estaba dando otra razón por la cual (diferente a la suya) la solución no funcionaría. No era mi intención criticarte. :-) –