我听说c++的类成员函数模板不能是虚的。这是真的吗?
如果它们可以是虚拟的,那么有什么场景可以使用这样的函数呢?
我听说c++的类成员函数模板不能是虚的。这是真的吗?
如果它们可以是虚拟的,那么有什么场景可以使用这样的函数呢?
当前回答
不,他们不能。但是:
template<typename T>
class Foo {
public:
template<typename P>
void f(const P& p) {
((T*)this)->f<P>(p);
}
};
class Bar : public Foo<Bar> {
public:
template<typename P>
void f(const P& p) {
std::cout << p << std::endl;
}
};
int main() {
Bar bar;
Bar *pbar = &bar;
pbar -> f(1);
Foo<Bar> *pfoo = &bar;
pfoo -> f(1);
};
如果您想要做的只是拥有一个公共接口并将实现推迟到子类,则效果大致相同。
其他回答
在虚函数的情况下如何调用正确的函数?
虚表将包含类的每个虚函数的条目,在运行时,它将选择特定函数的地址,并调用各自的函数。
如何正确的函数必须被调用在虚拟情况下连同函数模板?
在函数模板的情况下,用户可以使用任何类型调用该函数。这里相同的函数根据类型有几个版本。现在,在这种情况下,对于同一个函数,由于版本不同,必须维护vtable中的许多项。
不,他们不能。但是:
template<typename T>
class Foo {
public:
template<typename P>
void f(const P& p) {
((T*)this)->f<P>(p);
}
};
class Bar : public Foo<Bar> {
public:
template<typename P>
void f(const P& p) {
std::cout << p << std::endl;
}
};
int main() {
Bar bar;
Bar *pbar = &bar;
pbar -> f(1);
Foo<Bar> *pfoo = &bar;
pfoo -> f(1);
};
如果您想要做的只是拥有一个公共接口并将实现推迟到子类,则效果大致相同。
如果预先知道模板方法的类型集,则'虚拟模板方法'有一个变通方法。
为了说明这个想法,在下面的例子中只使用了两种类型(int和double)。
在那里,一个“虚拟”模板方法(Base:: method)调用相应的虚拟方法(Base:: VMethod之一),后者反过来调用模板方法实现(Impl::TMethod)。
只需要在派生实现(AImpl, BImpl)中实现模板方法TMethod,并使用derived <*Impl>。
class Base
{
public:
virtual ~Base()
{
}
template <typename T>
T Method(T t)
{
return VMethod(t);
}
private:
virtual int VMethod(int t) = 0;
virtual double VMethod(double t) = 0;
};
template <class Impl>
class Derived : public Impl
{
public:
template <class... TArgs>
Derived(TArgs&&... args)
: Impl(std::forward<TArgs>(args)...)
{
}
private:
int VMethod(int t) final
{
return Impl::TMethod(t);
}
double VMethod(double t) final
{
return Impl::TMethod(t);
}
};
class AImpl : public Base
{
protected:
AImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t - i;
}
private:
int i;
};
using A = Derived<AImpl>;
class BImpl : public Base
{
protected:
BImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t + i;
}
private:
int i;
};
using B = Derived<BImpl>;
int main(int argc, const char* argv[])
{
A a(1);
B b(1);
Base* base = nullptr;
base = &a;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
base = &b;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
}
输出:
0
1
2
3
注: Base::Method对于实际代码来说实际上是多余的(VMethod可以被设为public并直接使用)。 我添加它,使它看起来像一个实际的“虚拟”模板方法。
C++ doesn't allow virtual template member functions right now. The most likely reason is the complexity of implementing it. Rajendra gives good reason why it can't be done right now but it could be possible with reasonable changes of the standard. Especially working out how many instantiations of a templated function actually exist and building up the vtable seems difficult if you consider the place of the virtual function call. Standards people just have a lot of other things to do right now and C++1x is a lot of work for the compiler writers as well.
什么时候需要模板成员函数?我曾经遇到过这样的情况,我试图用纯虚拟基类重构一个层次结构。这是一种执行不同策略的糟糕风格。我想将其中一个虚函数的实参更改为数值类型,而不是重载成员函数并覆盖所有子类中的每一个重载,我尝试使用虚模板函数(并且不得不发现它们不存在)。
模板都是关于编译器在编译时生成代码的。虚函数都是关于运行时系统确定在运行时调用哪个函数。
一旦运行时系统发现它需要调用模板化的虚函数,编译就完成了,编译器就不能再生成相应的实例了。因此,不能使用虚拟成员函数模板。
然而,结合多态性和模板产生了一些强大而有趣的技术,特别是所谓的类型擦除。