question regarding templatization of virtual function
I know that you cannot templatize a virtual function and I do understand the concept behind it. But I still need a way to get past some errors I am getting. I am able to make my stuff work, but it doesn't look right to me.
I have class called System
:
#include "Vector.h"
class System
{
virtual void VectorToLocal(Vector<T>& global_dir,const Vector<T>* global_pos = 0) const = 0;
};
class UnresolvedSystem : public System
{
virtual void VectorToLocal(Vector<T>& global_dir,const Vector<T>* global_pos = 0) const
{
//do something
}
};
In Vector.h
:
tenplate<typename T>
class Vector
{
//some functions
};
Now I want to templatize VectorToLocal
in system.h
to take just Vector<T>
, but I cannot do it, since it is a virtual function. I want a work-开发者_Go百科around. I know I can have VectorToLocal
take Vector<float>
, Vector<double>
, etc., as arguments, but I do not want to do it.
Member function templates cannot be virtual. No two ways about it.
But virtual member functions can take fully-defined types that just happen to use templates:
class System
{
public:
virtual void DoIt(vector<int>* v);
};
int main()
{
vector<int> v;
System s;
s.DoIt(&v);
return 0;
}
By the way, why are you implementing your own vector class?
Any of the common ways of eliminating virtual functions, like CRTP, will also help.
I do not know what you want to do with your vector, but sometimes it is possible to make the template-function call a virtual function that implements the actual behavior. In that case you would implement the template-version in you superclass, and make it call a non-template pure virtual there that does whatever you want to do. This usually only works, if you put restriction on the type-parameter:
#include "Vector.h"
class System
{
virtual void print( const std::string & ) const = 0;
template<class T>
void VectorToLocal(Vector<T>& global_dir,const Vector<T>* global_pos = 0) const {
print( T.GetName() );
}
};
class UnresolvedSystem : public System
{
virtual void print( const std::string & Name ) const {
std::cout << name << std::endl;
}
};
In this case, I assumed that T
has a member-function GetName
.
If you define a C++ template function, a new function implementation is created for each combination of template argument types. So a single function in source, could be one or hunderds functions in machine code. That's what helps to makes them fast.
Now, the compiler determines which versions of your function to generate by how it is called. If int
is never a type parameter, the compiler is not supposted to generate an implementation. Now if you make a call virtual, it gets hard to find out how it's used, and it could be that the definition of the function is not in the header file when compiling a function that uses the template function. Without the source code of the function, the compiler can't create the compiled function.
There's a few other impracticalities you face when C++ would allow virtual template functions. Like how virtual functions are typically implemented.
And that's probably the reason why C++ doesn't allow it. You may think you need it, but there's probably another way, which I'm sure people will help you find if you give us a little more detail on the requirements behind this code snippet.
You have several options, all depending on what you're trying to do.
If T
is somehow inherent to System
(e.g., if System
has member variables of type T
), you can make the entire class templated on it:
template< typename T >
class System
{
virtual void VectorToLocal(Vector<T>& global_dir,const Vector<T>* global_pos = 0) const = 0;
};
template< typename T >
class UnresolvedSystem : public System<T>
{
virtual void VectorToLocal(Vector<T>& global_dir,const Vector<T>* global_pos = 0) const
{
//do something
}
};
If T
's context is local to VectorToLocal
only, then a better design decision would be to factor the function outside the class:
template< typename T >
void VectorToLocal( System& s, Vector<T>& global_dir, ... )
{
// use s's public interface to make changes to the object
}
Can you provide more detail about the purpose of VectorToLocal
?
If what you want is to provide a single implementation point then can forward the call to a template
struct base {
virtual void f( int );
virtual void f( double );
};
struct derived : base {
virtual void f( int x ) { f_tmpl(x); }
virtual void f( double x ) { f_tmpl(x); }
template <typename T>
void f_tmpl( T x ) { // ... }
};
I bet that with a typelist you could actually generate the virtual functions, but that would probably just complicate the code.
精彩评论