【问题标题】:How to avoid code duplication or multiple iterations?如何避免代码重复或多次迭代?
【发布时间】:2011-11-18 08:33:35
【问题描述】:

考虑下面给出的代码:

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()。但是随后必须将打印女性数量的代码段从Myfunc 类的process() 方法复制到MyfuncSSN 类中。这里没有代码重用。

什么是更好的解决方案?

【问题讨论】:

  • bool sex??哪个是true? (为什么不使用enum,这才是真正的评论。)
  • 个人有 SSN。因此将PersonSSN 设计为一个单独的类是一个糟糕的设计。相反,SSN 应该作为 Person 本身的成员变量,IMO。只有当两个类之间存在 is 关系时,才会出现继承。
  • @Mahesh 让我们假设Person 结构已经存在。所以你建议应该修改Person 结构以添加另一个数据成员而不是派生一个新结构?我在想修改现有代码可能不是一个好主意。

标签: c++ oop code-reuse


【解决方案1】:

如果您在编译时谈论对象识别,那么答案可能只有一个 - 模板。根据您使用的容器类型,它会有所不同,但如果您使用 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.
}

编辑:

如果你想省略双重迭代,我唯一能想到的就是使用 signle 模板函数来迭代和打印两个连续男性之间的女性数量,调用另一个模板函数进行 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 额外打印女性之间的男性数量 - 它可能会不足,因为这两个操作(虽然相似)可能会变成不可能将不同类型的功能分成不同的部分。然后它将需要代码加倍或双重迭代 - 不要认为有办法绕过它。

注意:您可能(如 cmets 中的建议)切换到函数参数中的 const-references - 我更习惯使用隐式共享的 qt-containers,因此不需要它。

【讨论】:

  • 我想过这个解决方案,但这个解决方案要求我在两个模板专业化中剪切并粘贴print the number of females between two consecutive males 的代码。否则我必须遍历列表两次对吗?
  • 实际上,如果“打印两个连续男性之间的女性数量”是另一个模板函数,您可以避免重复代码。上面的例子也应该通过 const ref 传递列表:)
  • @fileoffset 如何将“打印两个连续男性之间的女性数量”作为另一个模板函数编写?
【解决方案2】:

这个例子在很多不同的层面上都是错误的:)

理想情况下,“Person”应该是一个类; “name”、“sex”和“SSN”都是基类的成员,而“process()”可以是 method() 或 virtual method()。

问:有没有机会把Person和PersonSSN改成类,把“process()”变成一个方法?

问:您的程序如何“知道”它是有“Person”记录还是“PersonSSN”记录?你能把它作为你的“process()”函数的参数吗?

附录 9.16.2011:

百万美元的问题是“您的代码如何区分 'Person' 和 'PersonSSN'?”

如果您使用类,您可以使用“typeof”(不满意),或者您可以将特定于类的行为与类方法联系起来(首选,以及“模板”建议所建议的内容)。

您还需要至少三个不同的类:“Person”类(看起来和行为都像人)、“PersonSSN”类(具有额外的数据和可能的额外行为)......和“ueber” -class”,知道如何计算人员和 PersonSSN。

所以是的,我建议应该有一些类HAS,或者使用“Persons”和“PersonSSNs”。

是的,您可以将代码分解为一个类使用“Process-count-consecutive”,另一个调用父类“Process-count-consecutive”,并添加一个新的“print ssn”。

【讨论】:

  • 我的实际问题属于对象识别领域,我制作了这个例子来说明我面临的问题,希望它能传达这个想法:) 我可以将它们转换为类。但是process() 方法要求所有Perosn 或PersonSSN 对象都可用以获得所需的答案(计算排序集合中男性之间的女性数量)。那么你是不是建议Person 类应该是一个容器类?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-18
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
相关资源
最近更新 更多