How to avoid code duplication or multiple iterations?
Consider the code given below:
struct Person{
enum sex{male,female};
int salary;
};
struct PersonSSN:public Person{
int ssn;
};
I have a container which contains either Person or PersonSSN only, (known at compile time) sorted in the ascending order of salary value. I have to write a function myfunc() which does the following.
void myfunc(){
if the container contains Person:
print the number of females between two consecutive males.
else if the container contains PersonSSN:
print the number of females between two consecutive males
and
the ssn of the males.
}
I have two solutions for this problem but both have some drawbacks.
Solution 1: If I write a function for printing the number of females between males and another function for printing the ssn, I have to iterate th开发者_JAVA技巧rough the data twice which is costly.
Solution 2: I can write two classes, Myfunc
, and MyfuncSSN
derived from Myfunc
and have a virtual function process()
. But then the code segment which prints the number females has to be copied from the process()
method of the Myfunc
class into MyfuncSSN
class. Here code re-use is not there.
What is a better solution?
If you are talking about object recognition at compile time, then the answer can be only one - templates. Depending on which kind of container you use it will vary a bit, but if you use std::list it would be
#include <list>
template <typename T>
void myfunc(std::list<T>);
template <>
void myfunc(std::list<Person> lst){
print the number of females between two consecutive males.
}
template <>
void myfunc(std::list<PersonSSN> lst){
print the number of females between two consecutive males
and
the ssn of the males.
}
EDIT:
if you want to ommit double iteration the only thing i can imagine to do would be to use signgle template function for iterating and printing the number of females between two consecutive males calling another templated function for ssn printing:
#include <list>
template <typename T>
void printperson(T p){}
template <>
void printperson(Person p){
// Do nothing - perhaps you might skip it and use generic implementation instead
}
template <>
void printperson(PersonSSN p){
print ssn of the person p if it is male.
}
template <typename T>
void myfunc(std::list<T>){
print the number of females between two consecutive males.
and while doing so call printperson(list_element);
}
This might work for this simple example, but i am sure that for more complicated examples - say you want to print addionally number of males between females for PersonSSN - it might come short, as those two operations (while similar) might turn out to be impossible to separate into part with functionality for different types. Then it will need code doubling or double iteration - don't think there is way around it.
Note: you might (as suggested in comments) switch to const-references in function-args - i am more used to qt-containers which use implicite sharing and therefore dont need it.
This example is so wrong on so many different levels :)
Ideally, "Person" would be a class; "name", "sex" and "SSN" would all be members of the base class, and "process()" would be either a method() or a virtual method().
Q: Is there any chance of changing Person and PersonSSN into classes, and making "process()" a method?
Q: How does your program "know" whether it's got a "Person" record, or a "PersonSSN" record? Can you make this a parameter into your "process()" function?
ADDENDUM 9.16.2011:
The million$ question is "How can your code distinguish between a 'Person' and a 'PersonSSN'?"
If you use a class, you can use "typeof" (unsatisfactory), or you can tie the class-specific behavor to a class method (preferred, and what was suggested with the "template" suggestion).
You also need at least THREE different classes: the "Person" class (which looks and behaves like a person), a "PersonSSN" class (which has the extra data and possibly extra behavior) ... and an "ueber-class" that knows how to COUNT Persons and PersonSSN's.
So yes, I'm suggesting there should be some class that HAS, or that USES "Persons" and "PersonSSNs".
And yes, you can factor your code that one class uses "Process-count-consecutive", and another calls the parent "Process-count-consecutive", and adds a new "print ssn".
精彩评论