c++ - 虚拟成员函数 ptr 的类型推导(错误?)

标签 c++ visual-c++

这是一个非常难以发现的细微错误示例,由不直观的类型推导引起。程序员从 NewValue() 函数中的模板参数类型推导中期望“var2”是“derived2”类型。实际发生的是 var2 的推导类型是 基类“derived1”。如果您在派生类中覆盖了 ConvertValue() 虚函数,那么它会按预期进行编译和工作。

我放入编译器中断行只是为了证明类型不匹配。问题是 NewValue<> 在许多地方使用,在这些地方意外的类型推导干净利落地给出了意外的结果。 此外,程序员希望能够只继承基类成员函数“ConvertValue()”,而不必在每个派生类中过载它,只是为了让 NewValue<> 按预期工作。

这是编译器正确解释的还是编译器错误?

class base 
{
    int x;

public:

    base() : x(10){}
    int value() const { return x; }
    void value( int val ) { x = val; }
};

class derived1 : public base
{
public:
    virtual void ConvertValue( int x) { value( Factor()*x); }
    virtual int Factor() const { return 2; }

};

class derived2 : public derived1
{
public:
    //virtual void ConvertValue( int x) { value( Factor()*x); }
    virtual int Factor() const { return 3; }

};

template<typename T>
T NewValue( void (T::*unitsFunc)(int), int value)
{
    T obj;
    (obj.*unitsFunc)(value);
    return obj;
}

int _tmain(int argc, _TCHAR* argv[])
{
    auto var1 = NewValue( &derived1::ConvertValue, 10 );
    auto var2 = NewValue( &derived2::ConvertValue, 10 );

    std::cout   << "Test type deduction from virtual member function" << std::endl << std::endl 
                << "This should have value of 20:   " << var1.value()  << std::endl 
                << "This should have value of 30:   " << var2.value()  << std::endl 
                << (var2.value() == 30 ? "CORRECT" : "INCORRECT - bad type deduction") << std::endl << std::endl ;

    // this will not compile because NewValue<>() is returning type "derived1" instead of "derived2" 
    derived2 test = NewValue( &derived2::ConvertValue, 10 );
    return 0;
}

最佳答案

不,这不是错误。每当您将 & 应用于 &derived2::ConvertValue 时,结果始终是指向声明了 ConvertValue 的类成员的指针。这意味着 &derived2::ConvertValue 结果的类型是 void (derived1::*)(int)。 (这也是为什么当你在 derived2 中覆盖它时,代码编译通过的原因)

但是,任何指向基类成员函数的指针都可以转换为指向派生类成员的指针。这是因为 derived2 的所有实例都继承了 derived1::ConvertValue 的成员函数。因此,您可以显式地告诉编译器这样转换它:

auto var2 = NewValue<derived2>( &derived2::ConvertValue, 10 );

关于c++ - 虚拟成员函数 ptr 的类型推导(错误?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17536684/

相关文章:

c++ - 二进制数据 JSONCPP

c++ - 将 C API 返回的 char* 转换为 C++ 字符串

c++ - 如何在全局范围内初始化结构/类

c++ - 如何比较 strstr(LPCWSTR, CHAR*);

c++ - 从应用程序特定文件夹加载自定义字体文件

c++ - 在没有 API Hook 或过滤驱动程序的情况下拦截文件\文件夹 I\O

c++ - 如何使用 L(或不使用)在变量中传递 unicode 字符串

c++ - C++ 中的正则表达式和双反斜杠

c++ - 为什么我们使用 enable_shared_from_this 模板?

visual-c++ - 未解析的外部符号_IID_IDXGIAdapter4