Two really similar classes in C++ with only one different method: how to implement?
I have two classes that are almost identical, besides one method. The classes have the same data part and all the member functions but one:
class A {
private:
double data;
public:
double calc(){
return data*data;
}
double especific(){
return 2.0*data;
}
}
and the second class is identical, besides the especific method.
This member function in particular needs all the member data to calculate, so passing by value or reference is not an option. Is there a way to implement this without a lot of code duplication? Either using only one class or using templates, but not inheritance (huge performance impact).
Thanks
EDIT: Thanks for all the resp开发者_JAVA百科onses. The Strategy pattern can help in my case, I will try it and see if it works. I'm avoiding virtual inheritance as the plague based on some tests that I did in a different program. This routine will be called everywhere, and performance is a very important factor.
This sounds like a job for the Strategy pattern. It can be implemented in this case as a template parameter. Often it would be implemented as a constructor parameter or a setter method on the class, but that would require inheritance to work properly.
In this case, something like:
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;
}
};
Then you can refer to:
A<DoubleStrategy> x;
A<TripleStrategy> y;
x
and y
will be of completely unrelated types, but it sounds like that's not what you want in this case.
Now, in my opinion using a virtual function and inheritance is the way to go. As someone else pointed out, the performance penalty isn't that large. However there are circumstances in which I could see that it would be a bad idea.
For example, if this class is intended to represent a vector in a graphics package and you're going to be doing the same transform to millions of them, then I could see how you would not want a virtual function call to be a part of the code that did the transform. In fact, you would want to avoid pointer dereferences of any kind of you could at all help it.
Maybe I'm missing the point but why not have a base class that implements all the common functionality and a pure virtual especific()
and then inherit this and have the child classes implement especific()
as required. Make the data
member protected.
class BaseA
{
protected:
double data;
public:
double calc(){
return data*data;
}
virtual double especific() = 0;
};
class A1 : BaseA
{
double especific()
{
return data * 2;
}
};
WRT to the huge performance impact of inheritance... I think this isn't likely unless the cost of vtable lookups is significant compared with the work being done in the method body and you're doing this in a tight loop what's consuming most of your application processing.
If you don't make any members virtual
and define your classes intelligently there should be no performance impact whatsoever from inheritence.
All inheritence is saying is "make this class like that one, but with this extra stuff". It is no different at runtime than if you'd typed the same stuff twice.
I suppose you could make a performance impact by doing a bunch of unnesscary stuff in the constructor for the parent class that the child classes don't need. But you won't be that stupid. I have faith in you.
Why two classes at all? If the classes share the same data, you may just want to implement both functions in one class.
class A {
private:
double data;
public:
double calc(){
return data*data;
}
double especific(){
return 2.0*data;
}
double eMoreSpecific() {
return 23.0*data;
}
have a base class with all the common stuff and derive the two classes from it
As others have pointed out
a) this is exactly what inheritance was designed for
b) there is no perfomance overhead whatsoever
c) there are no nasty gotchas lurking anywhere
Many people will comment on this and say 'ah but what about xxxx'; these will be valid comments for advanced and corner case use; except you are not going to do any of them based on the simplicity of what you asked for.
Check out the Strategy Pattern
You could have your class take a functor which especific then calls. You can supply different functors for different ways of calculating the output. There are several other ways you can implement Strategy as well.
I have a feeling that a Bridge pattern might be a good approach for you as it sounds like you want to have unique implementations for your common abstraction.
There are several ways to do this, many of which you've named:
- Inheritance from a common base class (which does most of the work), and virtual
especific()
- One class, with two slightly differently-named
especific()
methods (or overloaded methods) - Use template specialisation
- Have
A
andB
use some other classC
to do the majority of the work.
There may be others.
You'll need to choose one of these based on the semantics of your classes and application, and any other specific constraints or requirements.
check out the "inheritance pattern"
精彩评论