2010-09-03 55 views
1

我有两个几乎完全相同的类,除了一种方法。这些类具有相同的数据部分和除1之外的所有成员函数:C++中两个真正类似的类只有一个不同的方法:如何实现?

class A { 
private: 
    double data; 
public: 
    double calc(){ 
    return data*data; 
    } 
    double especific(){ 
    return 2.0*data; 
    } 
} 

除了特定的方法之外,第二类是相同的。

该成员函数特别需要所有成员数据来计算,所以传递值或引用不是一个选项。有没有很多代码重复实现这个方法?只使用一个类或使用模板,但不使用继承(巨大的性能影响)。

感谢

编辑:感谢所有的答复。战略模式可以帮助我,我会尝试一下,看看它是否有效。基于我在不同程序中做过的一些测试,我避免了虚拟继承作为瘟疫。这个例程将被称为无处不在,性能是一个非常重要的因素。

+10

为什么你认为继承将是一个“巨大的性能影响”? – 2010-09-03 22:39:41

+0

我同意奥利查尔斯沃思。你有没有运行一些性能工具来确定使用继承会严重影响你的性能? – linuxuser27 2010-09-03 22:41:51

+7

除非您使用虚拟方法,否则继承不会带来任何开销。 – doc 2010-09-03 22:47:28

回答

7

这听起来像是Strategy pattern的工作。它可以在这种情况下作为模板参数来实现。通常它将作为类的构造函数参数或setter方法实现,但这需要继承才能正常工作。

在这种情况下,像:

template <class SpecificStrategy> 
class A { 
private: 
    double data; 
public: 
    double calc(){ 
     return data*data; 
    } 
    double especific() { 
     return SpecificStrategy::especific(data); 
    } 
}; 

class DoubleStrategy { 
    static double especific(double data) { 
     return 2 * data; 
    } 
}; 
class TripleStrategy { 
    static double especific(double data) { 
     return 3 * data; 
    } 
}; 

然后,你可以参考一下:

A<DoubleStrategy> x; 
A<TripleStrategy> y; 

xy将是完全无关的类型,但它听起来像那不是你想要的在这种情况下。

现在,在我看来,使用虚拟函数和继承是最好的选择。正如其他人指出的那样,性能损失并不是那么大。不过,在某些情况下,我可以看到这是一个坏主意。

例如,如果此类旨在表示图形包中的矢量,并且您将对数百万个图形执行相同的转换,那么我可以看到如何不需要虚拟函数调用成为进行转换的代码的一部分。事实上,你会希望避免任何形式的指针解引用都可以帮助它。

+4

好的答案;作为一个方面说明,我经常会对那些将这种或那种技术标记为“模式”的人发笑。模式被认为是人的发明,还是他们被人看作是观察者?因为你称之为“战略模式”,我称之为“功能性编程”。 – 2010-09-03 22:54:28

+1

@San Jancinto - 理想情况下,模式是观察一个反复出现的结构。 :-) – Omnifarious 2010-09-03 22:57:05

+0

@San Jacinto:通常情况下,模式只不过是一种复杂而过于复杂的方式,用命令式语言来近似函数式编程。 :) – jalf 2010-09-03 22:59:27

2

与所有常见的东西,一个基类,并从它

得出两类正如其他人所指出的

一)这正是继承是专为

B)有没有性能比较开销任何

三)有没有讨厌的陷阱潜伏在任何地方

很多人将共同对此,说'啊,但xxxx怎么样';这些将是对高级和特殊情况使用的有效评论;除非你根据你所要求的简单性不会做任何其中的任何一个。

+0

感谢您的回答,但我认为我处于角落的情况。我只写了一个(非常)简化版本的问题。 – Ivan 2010-09-06 17:21:54

2

也许我错过了点,但是为什么没有实现所有的通用功能和纯虚especific()一个基类,然后继承这一点,并具有根据需要子类实现especific()。使data成员受到保护。

class BaseA 
{ 
protected: 
    double data; 
public: 
    double calc(){ 
    return data*data; 
    } 
    virtual double especific() = 0; 
}; 

class A1 : BaseA 
{ 
    double especific() 
    { 
    return data * 2; 
    } 
}; 

WRT继承的巨大性能的影响......我认为,除非虚函数表查找的成本与正在开展的工作方法体中进行,你在做这个比较是显著,这是不太可能紧张的循环消耗了大部分应用程序处理。

+0

这正是我的情况:在一个被称为数百万次的紧密循环中...... – Ivan 2010-09-06 17:21:08

0

我有一种感觉,Bridge pattern可能是一个很好的方法,因为它听起来像你想为你的共同抽象有独特的实现。

0

有几种方法可以做到这一点,其中有许多您已经命名:从公共基类

  • 继承(其中大部分工作的),和虚拟especific()
  • 一类,有两个略有不同名称的especific()方法(或重载方法)
  • 使用模板特
  • AB使用一些其他类C主要做工作的性质。

可能有其他的。

您需要根据您的类和应用程序的语义以及任何其他特定约束或要求来选择其中之一。

1

退房的Strategy Pattern

你可以有你的类采取何种especific然后调用一个函数对象。您可以为计算输出的不同方法提供不同的函子。您还可以通过其他几种方式实施战略。

2

如果您没有创建任何成员virtual并且智能地定义您的类,应该有没有任何性能影响继承

所有的继承意味着“让这个类像那样,但是有了这些额外的东西”。它在运行时没有什么不同,如果你输入了相同的东西两次。

我想你可以使一个性能的影响,通过在子类不需要的父类的构造函数中做一堆unistcary的东西。但你不会那么愚蠢。我相信你。

+0

感谢您的信仰! ;-)但是使用编译时模板比使用继承更快吗? – Ivan 2010-09-06 17:19:27

+0

@伊万 - 号为什么会这样?生成的代码没有任何不同的理由。唯一真正的区别是模板可能需要更长的时间来编译,而且更难以调试。 – 2010-09-07 12:44:55

2

为什么两个班呢?如果这些类共享相同的数据,则可能只想在一个类中实现这两个函数。

class A { 
private: 
    double data; 
public: 
    double calc(){ 
    return data*data; 
    } 
    double especific(){ 
    return 2.0*data; 
    } 
    double eMoreSpecific() { 
    return 23.0*data; 
} 
相关问题