模板成员函数 [英] Template member functions
问题描述
我想绕过模板成员函数不能是虚拟的这一事实.这是我的代码:
Hi,
I would like to bypass the fact that template member functions can''t be virtual. Here is my code:
class A
{
// abstract class
}
template <class T> class B : public class A
{
void SetValue(const T p_Value&);
T m_Value;
}
template <class T> void CVariable<T>::SetValue(const T& p_Value)
{
m_Value = p_Value ;
}
当我需要将模板对象(类型B< int> B< MyClass> ...)存储在列表中时,我有一个抽象类A可以将其概括化.
问题是我想从基类A做一个SetValue(),因为模板成员函数不能是虚拟的,所以这是不可能的.
我发现的唯一解决方案是使用抽象类型,以便SetValue()不再是模板方法:
As I need so store the template objects (of type B<int>, B<MyClass>...) in a list , I have an abstract class A to generalize them.
The problem is that I would like to do a SetValue() from the base class A which isn''t possible as template member functions can''t be virtual.
The only solution I found is to use an abstract type so that SetValue() is no more a template method:
template <class T>
class DataType : public DataTypeInterface
{
}
class A
{
// abstract class
virtual void SetValue(const DataTypeInterface p_Value&) = 0;
}
template <class T> class B : public class A
{
void SetValue(const DataTypeInterface p_Value&);
DataType<T> p_Value;
}
template <class T> void CVariable<t>::SetValue(const DataTypeInterface & p_Value)
{
// Here do a dynamic_cast to check type T
m_Value = p_Value ;
}
但是,我不想进行动态转换.有什么解决办法吗?
非常感谢.
Carole
However, I don''t want to do dynamic casts. Is there any solution?
Thanks a lot.
Carole
推荐答案
简单地说-不能.您不能在C ++中将虚拟方法和模板合并到一个派生对象中.您需要根据项目的业务需求在两者之间做出选择.
但是从我的接洽中,您需要通过基本类型进行调用,然后需要使用虚拟方法,这使您的选择更加容易;)
您只能使用模板类型的属性来增强派生类,但这远不及 virtual 和
To put simply - No. You cannot combine virtual methods and templates in C++ within a single derivation. You need to make a choice between the two, based on business requirements of your project.
But from what I pick up, you need to make calls through the base type, which then requires use of virtual methods, which makes your choice easier ;)
You can only enhance your derived classes with template-type properties, but that''s as far as virtual and template can dance with each other in C++ ;)
//问题是我想从基类A
// The problem is that I would like to do a SetValue() from the base class A
class A
{
public:
virtual bool CanAcceptValue(const COleVariant& cVal) const = 0;
virtual bool TrySetValue(const COleVariant& cVal) = 0;
};
是的,这将是一个设计问题:):
Yes, it would be a designe problem :) :
void testYourList(CYourVarList& list)
{
bool bResult(true);
POSITION pos(list.GetHeadPosition());
while (pos) {
COleVariant cVal(3);
A* pcVar(list.GetNext(pos));
// generalized call, but maybe without result :) :
bResult = pcVar->TrySetValue(cVal) && bResult;
}
ASSERT(bResult); // not all vars could be set :)
}
换句话说:即使是A::SetValue(..)
的广义"形式
您将需要有关A对象类型的信息以使设置成功.
这就是为什么我只将不明确的功能概括化的原因:
In other words: even in the "generalized" form of A::SetValue(..)
you will need info about the type of an A-object to have the success of the setting.
That''s why I would generalize only the unspecific functions:
class A
{
public:
virtual void GetValueAsXMLString(CString& cszValue) const = 0;
};
...并使模板函数的参数变得奇怪:)
...and let the template functions be strange by their parameters :)
您必须问自己的第一个问题是...
在系列B<T>
的每个类的每个对象上,哪些操作在语义上等效?如果所有B<T>
的操作都是通用的,那么您可以将其粘贴在接口中并在每个派生类中实现,如果不是,您甚至不应该尝试.A
中定义的任何内容都必须独立于B<T>
中定义的任何内容-包括其模板参数.
设置器绝不会在语义上等效,除非您希望能够执行以下操作:
The first question you have to ask yourself is...
Which operations are semantically equivalent on every object of each class of the familyB<T>
? If an operation is common to allB<T>
then you can stick it in an interface and implement it in each derived class, if it''s not you shouldn''t be even trying. Anything defined inA
has to be independent of anything defined inB<T>
- including its template parameter.
Setters are never semantically equivalent, unless you want to be able to do something like:
void do_something( A *a, int i, float f )
{
a->SetValue( i );
a->SetValue( f );
}
据您从您的评论中可以得知,您不希望这样做.但是像A::print( std::ostream & )
这样的东西可以在A
的它的定义中,而不依赖于B<T>
中的任何东西.
现在,如果您想执行类似原始问题"的操作,则可以使用一个非常讨厌的技巧:
which as far as I can tell from your comment you don''t want. However things like A::print( std::ostream & )
can be in A
''s its definition doesn''t rely on anything in B<T>
.
Now, if you want to do something like your original "problem" you can use a really nasty hack:
class A
{
public:
virtual void do_something_with_a_T( void * ) = 0;
};
template< typename T >
class B
{
public:
virtual void do_something_with_a_T( void *p )
{
T *t = static_cast< P * >( p );
// do something with *t here...
t;
}
};
class P
{
};
class Q
{
};
int main()
{
P p;
Q q;
B<p> b1;
A *a = &b1;
a->do_something_with_a_T( &p );
B<p> b2;
a = &b2;
a->do_something_with_a_T( &q );
}
按static_cast
和void *
的压力应该告诉您,这不是类型安全的,永远不会.
使用您提供的解决方案或等效的解决方案,可以提高类型安全性:
the pressence of the static_cast
and void *
should tell you this isn''t typesafe and never will be.
You can be more typesafe using the solution you came up with or an equivalent:
class C
{
};
template< typename T >
class D : public C
{
public:
virtual void do_something_with_a_T( T * )
{
}
};
template< typename T >
void do_something_with_a_T( C *c, T *t )
{
if( D<t> *p = dynamic_cast< D<t> >( c ) )
{
p->do_something_with( *t );
}
}
int main()
{
P p;
Q q;
D<p> d1;
C *c = &d1;
do_something_with_a_T( c, &p );
D<p> d2;
c = &d2;
do_something_with_a_T( c, &q );
}
的优点是不需要额外的类,并且即使完全没有意义,也是类型安全的.
因此,TLDR:
-您的初始设计是错误的,因为B<T>::SetValue
在语义上并不等同于所有T
-至少有两个讨厌的骇客,您发现其中一个
which has the advantage of not needing an additional class and is typesafe, if completely pointless.
So, TLDR:
- your initial design was wrong as B<T>::SetValue
wasn''t semantically equivalent for all T
- there are at least two nasty hacks, one of which you discovered
这篇关于模板成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!