Tu código se ve muy bien como si estuvieras acostumbrado a un idioma diferente: en C++, usar this->x
(por ejemplo) es relativamente inusual. Cuando el código está bien escrito, también lo está utilizando un descriptor de acceso o un mutador.
Aunque soy bastante inusual en este aspecto en particular, voy a dejar constancia (una vez más) diciendo que obligar al código del cliente a usar un acceso directo o un mutador directamente es una mala idea. Si honestamente tiene una situación en la que tiene sentido que el código del cliente manipule un valor en su objeto, entonces el código del cliente debe usar una asignación normal para leer y/o escribir ese valor.
Cuando/si necesita controlar qué valor se le asigna, la sobrecarga del operador le permite tomar ese control sin forzar la sintaxis de obtención/configuración desagradable en el código del cliente. Específicamente, lo que quiere es una clase de proxy (o plantilla de clase). Solo por un ejemplo, una de las situaciones más comunes donde las personas quieren obtener/configurar funciones es algo así como un número que se supone que está restringido a un rango particular. El setXXX
comprueba el nuevo valor para estar dentro del rango, y el getXXX
devuelve el valor.
Si desea que, una (bastante) plantilla simple puede hacer el trabajo mucho más limpia:
template <class T, class less=std::less<T> >
class bounded {
const T lower_, upper_;
T val_;
bool check(T const &value) {
return less()(value, lower_) || less()(upper_, value);
}
void assign(T const &value) {
if (check(value))
throw std::domain_error("Out of Range");
val_ = value;
}
public:
bounded(T const &lower, T const &upper)
: lower_(lower), upper_(upper) {}
bounded(bounded const &init)
: lower_(init.lower), upper_(init.upper)
{
assign(init);
}
bounded &operator=(T const &v) { assign(v); return *this; }
operator T() const { return val_; }
friend std::istream &operator>>(std::istream &is, bounded &b) {
T temp;
is >> temp;
if (b.check(temp))
is.setstate(std::ios::failbit);
else
b.val_ = temp;
return is;
}
};
Esto también hace que el código mucho más cerca de autodocumentado - por ejemplo, cuando se declara un objeto como: bounded<int>(1, 1024);
, es inmediatamente evidente que la intención es un número entero en el rango de 1 a 1024. La única parte que alguien podría encontrar abierta a la pregunta es si 1 y/o 1024 están incluidos en el rango.Esto es considerablemente diferente de definir un int en la clase, y esperar que todos los que ven la clase se den cuenta de que se supone que usan el setXXX para imponer algunos límites (en ese momento desconocidos) sobre los valores que pueden ser asignado
Cuando incrusta uno de estos en una clase, lo convierte en una variable pública, y el rango se sigue aplicando. En el código del cliente, no existe un argumento real sobre la sintaxis: solo está asignando a una variable pública, como lo haría con cualquier otra, con el pequeño detalle de que al intentar asignar un valor fuera de rango emitirá una excepción. En teoría, la clase probablemente debería tomar un parámetro de plantilla de política para especificar exactamente lo que hace en ese caso, pero nunca tuve un motivo real para molestarme con eso.
es posible que desee editar sus ejemplos para reflejar su edición. En este momento está devolviendo un puntero no const. –
pero entonces yo mismo no podré borrar la memoria? Necesito saber cómo poseer correctamente las variables y dejar que otros llamen a los getters sin modificar la variable subordinada ... – Jonathan
getters y setters son muy estilo Java/C# (no C++). Son el resultado de la dependencia de estos idiomas en la reflexión y los marcos para construir el objeto. Getters y Setter destruyen la naturaleza OO de un idioma y explícitamente te permiten inmiscuirte en la estructura interna de un objeto. Esto es apon fruncido en C++ si es más común tener el objeto completamente formado después de que el constructor esté completo. –