繁体   English   中英

从(模板)基类内部调用虚拟成员函数

[英]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;

当然,如果Tstd::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM