从虚拟成员函数ptr中扣除类型(bug?)

时间:2013-07-08 21:57:37

标签: c++ visual-c++

这是一个非常难以找到的细微错误的例子,由非直观类型推断引起。程序员期望“var2”是NewValue()函数中模板参数类型推导的“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;
}

1 个答案:

答案 0 :(得分:1)

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

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

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