Repeated code w/ slightly different functions -- generic programming?

R

rlwebbnafex

Hello,

I have never used generic programming so I need a little help for an
idea on what I can do.
I have defined a lot of classes like the following. The classes are
all pretty much the same, they just represent data structures that I
need to use later. I create an vector of each of these data structures
later. It is just a record-keeping system. Anyhow, is there a way to
create a generic structure and define the few member functions I have?
For example, the copy constructor always simply copies those few
variables I have. The Check() function always just sees if the object
matches the outside object. The problem is the number and type of
those simple data types that I am checking, eg. bioSourceNum and name.
Because of those of I have to define all of the functions on all of
the classes. and later, the functions on the vectors that contain all
of these objects.

class Protein
{
public:
int bioSourceNum;
int unificationXrefNum;
string name;
string type;

bool isWritten;
Protein();
Protein(int, int, string, string, bool);
Protein(const Protein&);

int Check(int a, int b, string c, string d);
Protein& operator =(const Protein&);

};

class Complex
{
public:
int sequenceParticipantNum1;
int sequenceParticipantNum2;
string name;

bool isWritten;
Complex();
Complex(int, int, string, bool);
Complex(const Complex&);

int Check(int a, int b, string c);
Complex& operator =(const Complex&);

};
 
T

tony_in_da_uk

Hello,

I have never used generic programming so I need a little help for an
idea on what I can do.
I have defined a lot of classes like the following. The classes are
all pretty much the same, they just represent data structures that I
need to use later. I create an vector of each of these data structures
later. It is just a record-keeping system. Anyhow, is there a way to
create a generic structure and define the few member functions I have?
For example, the copy constructor always simply copies those few
variables I have. The Check() function always just sees if the object
matches the outside object. The problem is the number and type of
those simple data types that I am checking, eg. bioSourceNum and name.
Because of those of I have to define all of the functions on all of
the classes. and later, the functions on the vectors that contain all
of these objects.

class Protein
{
public:
int bioSourceNum;
int unificationXrefNum;
string name;
string type;

bool isWritten;
Protein();
Protein(int, int, string, string, bool);
Protein(const Protein&);

int Check(int a, int b, string c, string d);
Protein& operator =(const Protein&);

};

class Complex
{
public:
int sequenceParticipantNum1;
int sequenceParticipantNum2;
string name;

bool isWritten;
Complex();
Complex(int, int, string, bool);
Complex(const Complex&);

int Check(int a, int b, string c);
Complex& operator =(const Complex&);

};

When your data members have simple value semantics (like int, double,
string), the default compiler-generated copy-constructor and operator=
function are adequate - no need to write your own. Similarly, you can
replace Check with an operator== (which you will have to write
yourself :-( ) and compare to a temporary. It'll look like this:

class Protein
{
public:
int a_;
int b_;
string c_;
string d_;
bool e_;

Protein(); // if you need it...
Protein(int a, int b, string c, string d, bool e)
: a_(a), b_(b), c_(c), d_(d), e_(e)
{ }

bool operator==(const Protein& rhs) {
return a_ == rhs.a_ && b_ == rhs.b_ && c_ == rhs.c_ && d_ ==
rhs.d_;
}
};

int main()
{
Protein a(4, 8, "c here", "d there", true);

Protein b(a);

b = a;
cout << (b == Protein(10, 12, "c here", "", true)) << '\n'
<< (b == Protein(4, 8, "c here", "d there", true)) << '\n';
b = Protein(10, 12, "c here", "", true);
cout << (b == Protein(10, 12, "c here", "", true)) << '\n'
<< (b == Protein(4, 8, "c here", "d there", true)) << '\n';
}

Cheers,
Tony
 
R

rlwebbnafex

When your data members have simple value semantics (like int, double,
string), the default compiler-generated copy-constructor and operator=
function are adequate - no need to write your own. Similarly, you can
replace Check with an operator== (which you will have to write
yourself :-( ) and compare to a temporary. It'll look like this:

class Protein
{
public:
int a_;
int b_;
string c_;
string d_;
bool e_;

Protein(); // if you need it...
Protein(int a, int b, string c, string d, bool e)
: a_(a), b_(b), c_(c), d_(d), e_(e)
{ }

bool operator==(const Protein& rhs) {
return a_ == rhs.a_ && b_ == rhs.b_ && c_ == rhs.c_ && d_ ==
rhs.d_;
}

};

int main()
{
Protein a(4, 8, "c here", "d there", true);

Protein b(a);

b = a;
cout << (b == Protein(10, 12, "c here", "", true)) << '\n'
<< (b == Protein(4, 8, "c here", "d there", true)) << '\n';
b = Protein(10, 12, "c here", "", true);
cout << (b == Protein(10, 12, "c here", "", true)) << '\n'
<< (b == Protein(4, 8, "c here", "d there", true)) << '\n';

}

Cheers,
Tony


Hello, thanks very much, however, my question is: can I define a
generic class that, it does not matter how many data members I have;
a,b,c,d,e,f,g,h, etc. etc. (or how few), the == operator you have
defined will be instructed to check all those data members. This way I
don't have to define 100 different classes, eg. Protein, Complex,
BioChemicalReaction, DNA, RNA, etc.
 
M

Michael DOUBEZ

(e-mail address removed) a écrit :
When your data members have simple value semantics (like int, double,
string), the default compiler-generated copy-constructor and operator=
function are adequate - no need to write your own. Similarly, you can
replace Check with an operator== (which you will have to write
yourself :-( ) and compare to a temporary. It'll look like this:
[snip]

I don't understand his concern like you do: my understanding is that he
wants to copy all data member except some (isWritten in his example).

The problem with his approach is that the classes have two
responsibilities: holding the data and keeping track whether the it is
written or not. He should separate the two:

//first define the data stored
// like you said, the constructors, copy and comparison
// operators are generated automatically

struct Protein_Data
{
int bioSourceNum;
int unificationXrefNum;
string name;
string type;
};

struct Complex_Data
{
int sequenceParticipantNum1;
int sequenceParticipantNum2;
string name;
};

//2nd Define the operations of a record:

template<class DATA>
class record
{

public:
record(const record& r):isWritten(false),data(r.data){}
record& operator=(const record& r)
{
isWritten=false;
data=r.data;
}

//keeping parameter constructors
template<typename T1>
record(const T1 &p1):sWritten(false),data(p1){}
template<typename T1,typename T2>
record(const T1& p1,const T2& p2):sWritten(false),data(p1,p2){}
template<typename T1,typename T2,typename T3>
//.... do the same for check (if really needed)

bool operator==(const record& r)const
{
return data==r.data;
}

bool isWritten;

private:
DATA data;
};

typedef record<Protein_Data> Protein;
typedef record<Complex_Data> Complex;

And then:

Protein p4(4,42,"P4","P");
 
T

tony_in_da_uk

can I define a
generic class that, it does not matter how many data members I have;
a,b,c,d,e,f,g,h, etc. etc. (or how few), the == operator you have
defined will be instructed to check all those data members. This way I
don't have to define 100 different classes, eg. Protein, Complex,
BioChemicalReaction, DNA, RNA, etc.

If you want distinct classes, then you can easily write a program (in C
++ or some other language like Perl or a UNIX shell) to produce the C+
+ source code you want from some flatfile input ala "classname: type
idn; ... classname2: type idn; ...".

Off the top of my head, roughly:

string s;
map<string /*type*/, string /*idn*/> members;
string classname;
while (cin >> s)
{
if (classname.empty()) {
classname = s;
members.clear();
assert(cin >> s && s == "{");
} else if (s == "};") {
generate_class(classname, members);
} else {
string idn;
assert(cin >> idn && idn[idn.length() - 1] == ';');
members == idn.substr(0, idn.length() - 2);
}
}

And put "cout << "class " << classname << " {\n" ... etc. into your
generate_class() function...

Alternatively, if you don't need compile checks on usage, you could
perhaps put the data into a std::map from (identifier) string to
(value) string, converting numbers to/from string representations; or
use set of maps ala map<string, int>, map<string, string>; or some
map<string, variant> (boost library has a couple types of variants).

Cheers,

Tony
 
J

James Kanze

I have never used generic programming so I need a little help
for an idea on what I can do.
I have defined a lot of classes like the following. The
classes are all pretty much the same, they just represent data
structures that I need to use later. I create an vector of
each of these data structures later. It is just a
record-keeping system. Anyhow, is there a way to create a
generic structure and define the few member functions I have?
For example, the copy constructor always simply copies those
few variables I have. The Check() function always just sees if
the object matches the outside object. The problem is the
number and type of those simple data types that I am checking,
eg. bioSourceNum and name. Because of those of I have to
define all of the functions on all of the classes. and later,
the functions on the vectors that contain all of these
objects.
class Protein
{
public:
int bioSourceNum;
int unificationXrefNum;
string name;
string type;
bool isWritten;
Protein();
Protein(int, int, string, string, bool);
Protein(const Protein&);
int Check(int a, int b, string c, string d);
Protein& operator =(const Protein&);
};
class Complex
{
public:
int sequenceParticipantNum1;
int sequenceParticipantNum2;
string name;
bool isWritten;
Complex();
Complex(int, int, string, bool);
Complex(const Complex&);
int Check(int a, int b, string c);
Complex& operator =(const Complex&);
};

It sounds to me like the simplest solution would be some sort of
external code generator. It would only take a few lines of AWK
to convert something like:

[Protein]
bioSourceNum int
unificationXrefNum int
name string
type string
[Complex]
sequenceParticipantNum1 int
sequenceParticipantNum2 int
name string

into files Protein.hh, Protein.cc, Complex.hh and Complex.cc,
with the contents you need.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,252
Latest member
MeredithPl

Latest Threads

Top