Je suis actuellement en train de mettre en œuvre un système avec un certain nombre de classes représentant des objets tels que client, entreprise, produit, etc. Comme on pourrait s'y attendre, chaque classe a un certain nombre d'attributs standard.Agrégation générique d'objets C++ par attribut lorsque le nom d'attribut est inconnu au moment de l'exécution
J'ai une longue liste d'exigences essentiellement identiques tels que:
- la possibilité de récupérer toutes les affaires dont l'industrie est la fabrication.
- la possibilité de récupérer tous les clients basés à Londres
classe affaires a attribuer le secteur et le client a l'attribut emplacement. Il est clair que ce problème relationnel et pseudo SQL ressemblerait à quelque chose comme:
SELECT ALL business in business' WHERE sector == manufacturing
Malheureusement brancher dans un DB n'est pas une option.
Ce que je veux faire est d'avoir une seule fonction d'agrégation générique dont la signature prendrait la forme:
vector<generic> genericAggregation(class, attribute, value);
Où est la classe d'objet que je veux agréger, attribut et valeur étant l'attribut de classe et valeur d'intérêt. Dans mon exemple, j'ai mis vector comme type de retour, mais cela ne marcherait pas. Probablement mieux de déclarer un vecteur de type de classe pertinent et de le passer en argument. Mais ce n'est pas le problème principal. Comment puis-je accepter les arguments sous forme de chaîne pour la classe, l'attribut et la valeur, puis les mapper dans une fonction d'agrégation d'objets générique?
Comme il est impoli de ne pas afficher de code, voici un programme factice qui crée un tas d'objets de classes imaginatives. Inclus est une fonction d'agrégation spécifique qui retourne un vecteur d'objets B dont l'objet A est égal à un identifiant spécifié sur la ligne de commande, par ex. ..
$ ./aggregations 5
qui retourne tous les B dont les objets Un attribut 'i' est égal à 5. Voir ci-dessous:
#include <iostream>
#include <cstring>
#include <sstream>
#include <vector>
using namespace std;
//First imaginativly names dummy class
class A {
private:
int i;
double d;
string s;
public:
A(){}
A(int i, double d, string s) {
this->i = i;
this->d = d;
this->s = s;
}
~A(){}
int getInt() {return i;}
double getDouble() {return d;}
string getString() {return s;}
};
//second imaginativly named dummy class
class B {
private:
int i;
double d;
string s;
A *a;
public:
B(int i, double d, string s, A *a) {
this->i = i;
this->d = d;
this->s = s;
this->a = a;
}
~B(){}
int getInt() {return i;}
double getDouble() {return d;}
string getString() {return s;}
A* getA() {return a;}
};
//Containers for dummy class objects
vector<A> a_vec (10);
vector<B> b_vec;//100
//Util function, not important..
string int2string(int number) {
stringstream ss;
ss << number;
return ss.str();
}
//Example function that returns a new vector containing on B objects
//whose A object i attribute is equal to 'id'
vector<B> getBbyA(int id) {
vector<B> result;
for(int i = 0; i < b_vec.size(); i++) {
if(b_vec.at(i).getA()->getInt() == id) {
result.push_back(b_vec.at(i));
}
}
return result;
}
int main(int argc, char** argv) {
//Create some A's and B's, each B has an A...
//Each of the 10 A's are associated with 10 B's.
for(int i = 0; i < 10; ++i) {
A a(i, (double)i, int2string(i));
a_vec.at(i) = a;
for(int j = 0; j < 10; j++) {
B b((i * 10) + j, (double)j, int2string(i), &a_vec.at(i));
b_vec.push_back(b);
}
}
//Got some objects so lets do some aggregation
//Call example aggregation function to return all B objects
//whose A object has i attribute equal to argv[1]
vector<B> result = getBbyA(atoi(argv[1]));
//If some B's were found print them, else don't...
if(result.size() != 0) {
for(int i = 0; i < result.size(); i++) {
cout << result.at(i).getInt() << " " << result.at(i).getA()->getInt() << endl;
}
}
else {
cout << "No B's had A's with attribute i equal to " << argv[1] << endl;
}
return 0;
}
Compile avec:
g++ -o aggregations aggregations.cpp
Si vous souhaitez :) Au lieu d'implémenter une fonction d'agrégation séparée (c'est-à-dire getBbyA() dans l'exemple), je souhaiterais avoir une seule fonction d'agrégation générique. nction qui prend en compte toutes les paires d'attributs de classe possibles, de sorte que toutes les conditions d'agrégation sont respectées. Si des attributs supplémentaires sont ajoutés ultérieurement ou si des conditions d'agrégation supplémentaires sont requises, elles seront automatiquement prises en compte.
Il y a donc quelques problèmes ici, mais le principal que je cherche à comprendre est comment mapper un argument d'exécution à un attribut de classe.
J'espère avoir fourni suffisamment de détails pour décrire adéquatement ce que j'essaie de faire ...
Pouvez-vous modifier les classes? (Vous allez avoir des problèmes si vous ne pouvez pas.) – Beta
@Beta: pas nécessairement, on pourrait aussi penser à des objets Fonction étant définis pour ces accès. Il y a beaucoup de possibilités. –
@ Matthieu M .: Je ne comprends pas. Je ne peux penser qu'à deux façons de le faire sans écrire une routine séparée pour chaque domaine de chaque classe: 1) modifier les classes ou 2) en utilisant des macros [shudder]. J'apprendrais volontiers une autre façon ... – Beta