(quand c'est moi qui note)
Les variables globales nuisent à la lisibilité du code. S'il y a des variables globales, les entrées de vos fonctions peuvent être n'importe quoi : on ne sait pas si des valeurs issues de variables globales seront utilisées en entrées ou pas.
Si toutes les données sont accessibles par variable globale, alors on ne sait rien du tout des entrées de vos fonctions.
Si vous n'avez pas de variable globale, on voit dès la signature de la fonction quelles sont les entrées :
std::vector<Animal> animaux;
std::vector<Gerant> gerants;
std::string getNom(std::string id);
// A priori, cette fonction va utiliser une variable globale. Peut-être
// que ça va la modifier ? J'en sais rien.
std::string getNom(std::string id, const std::vector<Animal> & animaux);
// Ok
void foo(const Animal animal) { // Ok la valeur de animal n'est pas modifiée
const std::string name = animal.getName(); // ok le nom ne changera pas
// ...
}
size_t count_tigers(std::vector<Animal> animals) {
// S'il y a 10000 animaux, on viens de copier 10000 animaux
size_t count = 0;
for (Animal animal : animals) { // Et on copie encore une fois chaque animal
if (animal.getEspece() == "Tiger") {
++count;
}
}
return count;
}
size_t count_tigers(const std::vector<Animal> & animals) { // ok on ne recopie pas
size_t count = 0;
for (const Animal & animal : animals) { // Ok on ne recopie pas
if (animal.getEspece() == "Tiger") {
++count;
}
}
return count;
}
Lorsque vous écrivez une classe, par défaut, le compilateur vous crée :
- Un constructeur par copie qui consiste à recopier tous les membres
- Un opérateur d'affectation par copie qui consiste à recopier tous les membres
- Un destructeur qui consiste à détruire tous les membres
Si vous n'avez pas de pointeur possédés (T * remplis avec new), et pas de ressource particulière allouée explicitement (comme des FILE *), et pas d'héritge, vous n'avez surement pas définir tout ça :
// .h
class Animal {
public:
Animal(std::string nom, std::string espece, int taille, int age);
Animal(const Animal &);
Animal= operator=(const Animal &);
~Animal();
std::string getName();
std::string getEspece();
int getTaille();
int getAge();
private:
std::string name;
std::string espece;
int taille;
int age;
};
// .cpp
Animal::Animal(std::string nom, std::string espece, int taille, int age)
: nom(nom), espece(espece), taille(taille), age(age) {
}
Animal::Animal(const Animal & other)
: nom(other.nom),
espece(other.espece),
taille(other.taille),
age(other.age)
{
}
Animal & Animal::operator=(const Animal & other) {
if (this == &other) return *this;
nom = other.nom;
espece = other.espece;
taille = other.taille;
age = other.age;
return *this;
}
~Animal() {
}
std::string Animal::getName() {
return name;
}
std::string Animal::getEspece() {
return espece;
}
int Animal::getTaille() {
return taille;
}
int getAge() {
return age;
}
Le même code en plus court :
// .h
class Animal {
public:
Animal(std::string nom, std::string espece, int taille, int age);
std::string getName() const { return name; }
std::string getEspece() const { return espece; }
int getTaille() const { return taille; }
int getAge() const { return age; }
private:
std::string name;
std::string espece;
int taille;
int age;
};
// .cpp
Animal::Animal(std::string nom, std::string espece, int taille, int age)
: nom(nom), espece(espece), taille(taille), age(age) {
}
(La communauté préfère d'ailleurs la seconde version qui suit le "Rule of 0" : https://en.cppreference.com/w/cpp/language/rule_of_three)
On vous a surement appris :
size_t sum_ages(const std::vector<Animal> & animals) {
int sum = 0;
for (std::vector<Animal>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
sum += it->getAge();
}
return sum;
}
Le type std::vector<Animal>::const_iterator
est long à écrire, long à lire, et est peu informatif. Ecrivez auto à la place.
size_t sum_ages(const std::vector<Animal> & animals) {
int sum = 0;
for (auto it = animals.begin(); it != animals.end(); ++it) {
sum += it->getAge();
}
return sum;
}
Ou mieux : n'écrivez pas d'itérateur et utilisez une Range-based for loop :
size_t sum_ages(const std::vector<Animal> & animals) {
int sum = 0;
for (const Animal & animal : animals) {
sum += animal.getAge();
}
return sum;
}
Please pardon my English. Also, I haven't written C++ since 95 (switched to Java, supplemented with other langs since), so perhaps there's something new I'm somehow unaware of. For the last example, shouldn't "it->getAge()" be "animal->getAge()"?