[英]Calling a virtual member function from inside the (template) base class
假设我有以下内容:
#include <iostream>
#include <string>
template<class T>
class base
{
public:
void print()
{
T t = get();
std::cout << t << std::endl;
}
virtual T get() const
{
// assumes T can be constructed from, say, -1
T t = -1.0;
return t;
}
};
class derived : public base<std::string>
{
public:
virtual std::string get() const
{
// this is a silly example, but one can
// imagine that what we return here could
// depend on data members of derived
return "this is a string";
}
};
int main()
{
derived d;
d.print();
return 0;
}
在我看来, d.print()
应该调用derived::get()
因为get()
是虚拟的。 但是,我收到编译器错误,说我无法将string
初始化为-1.0
,这意味着当我调用d.print()
时,编译器正在尝试调用base::get()
d.print()
。 这是怎么回事?
但是,我收到编译器错误,说我无法将字符串初始化为-1.0,这意味着当我调用d.print()时,编译器正在尝试调用base :: get()。
不,编译器错误意味着编译器正在尝试实例化base<std::string>::get()
,它必须这样做,因为derived
使用base<std::string>
作为基类。 仅仅因为你没有调用函数并不意味着你不能 。 你仍然可以直接调用base<std::string>::get()
。
您实例化了base<std::string>
并将其用作基类。 由于base<std::string>::get()
是一个虚函数,因此使用base<std::string>
作为基类这一事实将其视为“使用”。 由于它正在使用中,因此必须进行实例化。 因此编译器必须并将尝试编译该函数。
由于std::string
不能从float中隐式构造,因此编译器会因失败的模板替换而出错。
当您隐式实例化一个类模板,仅使用这些成员函数将被实例化,因为你已经知道了,否则你就不会问这个。 问题是标准中的使用定义可能不完全符合您的预期,特别是,如果它不是纯粹的话,任何虚函数都会被使用
§3.2p2[...]如果虚拟成员函数不纯,则使用它是有用的。[...]
这意味着即使您的代码没有显式调用它也会使用base::get
,因此编译器将隐式实例化它并触发您看到的编译器错误。
T t = -1.0;
当然,如果T
是std::string
,这将无法编译。 它与get
virtual
无关,在运行时将调用哪个函数。 运行时在代码编译为机器代码后出现,您的代码甚至无法编译。
你为什么不这样做:
T t = T();
同样,它需要T
具有默认构造函数。
问题出在这个方法中(其中T = std :: string):
virtual T get() const
{
// assumes T can be constructed from, say, -1
T t = -1.0;
return t;
}
编译器是对的。 您不能使用double值初始化std :: string。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.