Как избежать дублирования кода или нескольких итераций? - PullRequest
0 голосов
/ 16 сентября 2011

Рассмотрим код, указанный ниже:

struct Person{
enum sex{male,female};
int salary;
};

struct PersonSSN:public Person{
int ssn;
};

У меня есть контейнер, который содержит только Person или PersonSSN (известный во время компиляции), отсортированный в порядке возрастания значения заработной платы. Я должен написать функцию myfunc (), которая делает следующее.

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.
}

У меня есть два решения этой проблемы, но у обоих есть некоторые недостатки.

Решение 1: Если я напишу функцию для печати числа женщин между мужчинами и другую функцию для печати ssn, мне придется дважды просматривать данные дважды, что дорого.

Решение 2: Я могу написать два класса Myfunc и MyfuncSSN, производные от Myfunc и иметь виртуальную функцию process(). Но затем сегмент кода, который печатает число женщин, должен быть скопирован из метода process() класса Myfunc в класс MyfuncSSN. Здесь повторного использования кода не существует.

Какое решение лучше?

Ответы [ 2 ]

1 голос
/ 16 сентября 2011

Если вы говорите о распознавании объектов во время компиляции, то ответ может быть только один - шаблоны.В зависимости от того, какой тип контейнера вы используете, он может немного отличаться, но если вы используете std :: list, это будет

#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.
}

РЕДАКТИРОВАТЬ:

, если вы хотите пропустить двойную итерациюЕдинственное, что я могу себе представить, это использовать шаблонную функцию signgle для итерации и печати числа женщин между двумя последовательными мужчинами, вызывающими другую шаблонную функцию для печати ssn:

#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);
}

Это может работать в этом простом примере, но я уверен, что для более сложных примеров - скажем, вы хотите напечатать дополнительное число мужчин между женщинами для PersonSSN - это может оказаться коротким, поскольку эти две операции (хотя и похожие) могут оказаться невозможными разделить на части с функциональностьюдля разных типов.Тогда ему понадобится удвоение кода или двойная итерация - не думайте, что есть способ обойти это.

Примечание: вы можете (как это предлагается в комментариях) переключаться на const-ссылки в аргументах-функциях - я больше используюк qt-контейнерам, которые используют неявное совместное использование и поэтому не нуждаются в этом.

0 голосов
/ 16 сентября 2011

Этот пример неверен на многих разных уровнях:)

В идеале "Человек" был бы классом; «name», «sex» и «SSN» будут членами базового класса, а «process ()» будет либо method (), либо виртуальным методом ().

В: Есть ли шанс изменить Person и PersonSSN на классы и сделать метод "process ()"?

В: Как ваша программа «узнает», есть ли запись «Person» или «PersonSSN»? Можете ли вы сделать это параметром в вашей функции "process ()"?

ADDENDUM от 16.09.2011 :

Вопрос на миллион долларов: «Как ваш код различает« Person »и« PersonSSN »?»

Если вы используете класс, вы можете использовать «typeof» (неудовлетворительно) или привязать поведение, специфичное для класса, к методу класса (предпочтительнее, и то, что было предложено с предложением «шаблона»).

Вам также необходимо по крайней мере ТРИ различных класса: класс "Person" (который выглядит и ведет себя как человек), класс "PersonSSN" (который имеет дополнительные данные и, возможно, дополнительное поведение) ... и "ueber". -класс ", который знает, как СЧИТАТЬ Персоны и Персоны.

Так что да, я предполагаю, что должен быть какой-то класс, который ИМЕЕТ или ИСПОЛЬЗУЕТ"Persons" и "PersonSSNs".

И да, вы можете учесть в своем коде, что один класс использует «Process-count-countcutive», а другой вызывает родительский «Process-count-последовательный» и добавляет новый «print ssn».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...