Generic Aggregation of C++ Objects by Attribute When Attribute Name is Unknown at Runtime
- by stretch
I'm currently implementing a system with a number of class's representing objects such as client, business, product etc. Standard business logic. As one might expect each class has a number of standard attributes.
I have a long list of essentially identical requirements such as:
the ability to retrieve all business' whose industry is manufacturing.
the ability to retrieve all clients based in London
Class business has attribute sector and client has attribute location. Clearly this a relational problem and in pseudo SQL would look something like:
SELECT ALL business in business' WHERE sector == manufacturing
Unfortunately plugging into a DB is not an option.
What I want to do is have a single generic aggregation function whose signature would take the form:
vector<generic> genericAggregation(class, attribute, value);
Where class is the class of object I want to aggregate, attribute and value being the class attribute and value of interest. In my example I've put vector as return type, but this wouldn't work. Probably better to declare a vector of relevant class type and pass it as an argument. But this isn't the main problem.
How can I accept arguments in string form for class, attribute and value and then map these in a generic object aggregation function?
Since it's rude not to post code, below is a dummy program which creates a bunch of objects of imaginatively named classes. Included is a specific aggregation function which returns a vector of B objects whose A object is equal to an id specified at the command line e.g. ..
$ ./aggregations 5
which returns all B's whose A objects 'i' attribute is equal to 5. See below:
#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 with:
g++ -o aggregations aggregations.cpp
If you wish :)
Instead of implementing a separate aggregation function (i.e. getBbyA() in the example) I'd like to have a single generic aggregation function which accounts for all possible class attribute pairs such that all aggregation requirements are met.. and in the event additional attributes are added later, or additional aggregation requirements, these will automatically be accounted for.
So there's a few issues here but the main one I'm seeking insight into is how to map a runtime argument to a class attribute.
I hope I've provided enough detail to adequately describe what I'm trying to do...