Stai confondendo le variabili globali per le variabili membro.
La modifica delle variabili membro nelle funzioni membro va bene, quando la funzione ha lo scopo di modificare lo stato della classe. Questo è il motivo per cui OOP è nato in primo luogo: raggruppare logicamente stato e comportamento. Se sta diventando difficile tenere traccia di ciò che sta accadendo alle variabili membro, non è un problema usarle, il problema è che la tua classe è troppo grande.
Se si stanno passando variabili ininterrottamente, si potrebbe anche non utilizzare alcuna funzionalità OOP.
Un'altra cosa da considerare, è che se la modifica delle variabili membro fosse considerata imprudente, allora quale sarebbe il punto di una funzione setter?
Diamo un'occhiata a un esempio di buffer circolare, scritto in C, barrato da Pagina Wiki :
/* Opaque buffer element type. This would be defined by the application. */
typedef struct { int value; } ElemType;
/* Circular buffer object */
typedef struct {
int size; /* maximum number of elements */
int start; /* index of oldest element */
int end; /* index at which to write new element */
ElemType *elems; /* vector of elements */
} CircularBuffer;
void cbInit(CircularBuffer *cb, int size) {
cb->size = size + 1; /* include empty elem */
cb->start = 0;
cb->end = 0;
cb->elems = calloc(cb->size, sizeof(ElemType));
}
void cbFree(CircularBuffer *cb) {
free(cb->elems); /* OK if null */
}
int cbIsFull(CircularBuffer *cb) {
return (cb->end + 1) % cb->size == cb->start;
}
int cbIsEmpty(CircularBuffer *cb) {
return cb->end == cb->start;
}
/* Write an element, overwriting oldest element if buffer is full. App can
choose to avoid the overwrite by checking cbIsFull(). */
void cbWrite(CircularBuffer *cb, ElemType *elem) {
cb->elems[cb->end] = *elem;
cb->end = (cb->end + 1) % cb->size;
if (cb->end == cb->start)
cb->start = (cb->start + 1) % cb->size; /* full, overwrite */
}
/* Read oldest element. App must ensure !cbIsEmpty() first. */
void cbRead(CircularBuffer *cb, ElemType *elem) {
*elem = cb->elems[cb->start];
cb->start = (cb->start + 1) % cb->size;
}
L'esempio C passa tutto via argomenti, trasportato attraverso una struttura. Questo perché C non offre funzioni OOP integrate, quindi è quello che devi fare.
Se lo facciamo in C ++, rendere tutto nella struct una variabile membro e accedervi 'globalmente' è del tutto appropriato:
class CircularBuffer
{
private:
int size; // maximum number of elements
int start; // index of oldest element
int end; // index at which to write new element
ElemType *elems; // vector of elements
public:
CircularBuffer(int cbSize) {
size = cbSize + 1; // include empty elem
start = 0;
end = 0;
elems = new ElemType[size];
}
~CircularBuffer() {
delete[] elems;
}
bool IsFull() {
return (end+1) % size == start;
}
bool IsEmpty() {
return end == start;
}
void Write(ElemType *elem) {
elems[end] = *elem;
end = (end + 1) % size;
if (end == start)
start = (start + 1) % size; //full, overwrite
}
//Read oldest element. App must ensure !IsEmpty() first.
void Read(ElemType *elem) {
*elem = elems[start];
start = (start + 1) % size;
}
}
Se invece avevi metodi che facevano qualcosa del genere:
void Write(ElemType *elem)
{
_Write(ElemType *elem, this->start, this->end, this->size);
}
o peggio, dovevo chiamare il membro in questo modo:
cb.Write(&elem,cb.start,cb.end,cb.size);
ci sarebbe molta rabbia.
Il punto è che le variabili start, end, size e elems fanno parte dello stato interno della classe, e quindi possono essere manipolate direttamente all'interno dei metodi delle classi. L'utente della classe può manipolarli solo attraverso le funzioni esposte, come parte di Information Hiding . Se stai solo passando le variabili a tutte le funzioni membro, come se scrivessi C, allora potresti anche usare C correttamente invece di compilarlo con un compilatore C ++.