Hi,
I have a class hierarchy with virtual methods:
(I dropped all safety issues like std::auto_ptr's etc. for brevity )
1 2 3 4 5 6 7 8 9 10
class B
{
public:
virtualvoid f();
}
class D : public B
{
public:
virtualvoid f();
}
In some cases I want to use the polymorphic behavior like in this:
1 2 3 4
void g(B* b)
{
b -> f();
}
But in cases it's not needed, I want to "disable" it, like in this:
1 2 3 4 5 6 7
void h()
{
D* d = new D();
for (int i = 0; i < 1000; ++i)
d->f(); // we know that "d" always hold's a D object not a descendant of D
delete d;
}
I don't want to pay for polymorphism if I don't need it ;-).
I know, that I can disable it by writing this:
1 2 3 4 5 6 7
void h_modified()
{
D* d = new D();
for (int i = 0; i < 1000; ++i)
d->D::f(); // this disables the polymorphic behaviour
delete d;
}
But since I want to use it in a more general manner, the upper solution doesn't work.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
template <class T>
class MyPtrClass
{
public:
MyPtrClass(T* t);
// should return something that "disables" virtual behavior
??? operator->(){????};
// cannot do this, since it should work for every function:
//void f(){t->T::f();};
private:
T* t;
}
The behavior I'd like to have is this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
void i()
{
D* d = new D();
B* b = d;
MyPtrClass<D> m(d);
m->f(); // should call d->D::f()
//cheating the type system...
MyPtrClass<B> n(b);
n->f(); // should call d->B::f() despite the fact that n really holds a D object!
delete d;
}
I don't think macros mix well with templates. I haven't tried it but I suppose the template parameters are not substituted for each separate template instantiation.
Besides, I don't think it contradicts OO.
Some classes just don't use virtual methods, because they cannot afford the costs incurred with them (think of the container classes) and therefore use compile time polymorphism (iterators and naming conventions).
This forces you to also use compile time polymorphism if you don't want to depend a concrete container type.
This idiom would let the user decide between performance or flexibility.
Each container would then have iterators derived from Iterator<T>, so instead of writing now:
1 2 3 4 5 6 7 8 9
template<class FwdIt>
void myFun(FwdIt begin, FwdIt end)
{
for ( ; begin != end; ++begin)
{
int a = *begin;
//...
}
}
one could skip the template:
1 2 3 4 5 6 7 8
void myFun(Iterator<int>& begin, Iterator<int>& end)
{
for ( ; begin != end; ++begin)
{
int a = *begin;
//...
}
}
But since this involves two extra virtual function calls in each iteration this is not desirable due to performance reasons. I think that's the reason why they chose not to implement the iterators as a class hierarchy.
You can choose Iterator<YourType>& in the interface, when you choose to be flexible
and choose VectorIterator<YourType> when your're not interested in the polymorphic behavior and are sure that VectorIterator is a leaf class!
No need to do that at all. Good compilers replace virtual calls with static calls if they know the type of the object. If they have access to the member function definition, they can even inline such calls. This is exactly the case here. Templates are not a problem at all, because templates are processed before the actual compilation (just as preprocessor macros) - the compiler sees the code with all types specified. Even if you have a stupid compiler, the cost is still not as high as you may think.
This is just one additional load, if it is in L1 cache (and in this loop it certainly is) most processors should do that in 1 or 2 cycles.