12

假设我有两个类,第一个用于编写原始类型(bool, int,float等),第二个扩展第一个以编写复杂类型:

struct Writer {
    virtual void Write(int value) = 0;
};

struct ComplexWriter : public Writer {
    template <typename TValue> void Write(const TValue &value) {
        boost::any any(value);
        Write(any);
    }
    //virtual void Write(int value) = 0; // see question below
    virtual void Write(const boost::any &any) = 0;
};

这个想法是,如果有人调用myWriter.Write(someIntValue);, int 重载将优先于模板化方法。

相反,我的编译器(Visual C++ 11.0 RC)总是选择模板方法。例如,以下代码片段将打印Wrote any到控制台:

struct ComplexWriterImpl : public ComplexWriter {
    virtual void Write(int value) { std::cout << "Wrote an int"; }
    virtual void Write(const boost::any &any) { std::cout << "Wrote any"; }
};

void TestWriter(ComplexWriter &writer) {
    int x = 0;
    writer.Write(x);
}

int main() {
    ComplexWriterImpl writer;
    TestWriter(writer);
}

当我Write(int)也在类中声明方法时,行为突然发生了变化ComplexWriter(请参阅第一个片段中的注释行)。然后打印Wrote an int到控制台。

这是我的编译器应该如何表现的吗?C++ 标准是否明确规定只有在同一类(而不是基类)中定义的重载才能优先于模板化方法?

4

2 回答 2

7

问题是,在您调用writer.Write(x)编译器时,编译器看到的是 aComplexWriter而不是 a ComplexWriterImpl,因此它只知道在ComplexWriter模板函数和函数中定义的boost::any函数。

ComplexWriter不包含任何接受 an 的虚函数int,因此它无法调用定义的 int 重载ComplexWriterImpl

当您将虚拟重载添加到ComplexWriter类时,编译器会意识到该类中有一个整数重载,ComplexWriter因此会调用它的实现ComplexWriterImpl

编辑:现在您已经在 ComplexWriter 和 Writer 之间的继承中进行了编辑,我为您提供了更完整的解释:

当您创建一个子类并在其中定义一个函数时,无论其参数类型如何,基类中该名称的所有函数都将被隐藏。

您可以使用我相信的 using 关键字来解决这个问题:

struct ComplexWriter : public Writer {
    template <typename TValue> void Write(const TValue &value) {
        boost::any any(value);
        Write(any);
    }
    using Writer::Write;
    virtual void Write(const boost::any &any) = 0;
};

有关更多详细信息,请参阅此常见问题解答条目: http: //www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

编辑2:只是为了确认这确实解决了你的问题:http: //ideone.com/LRb5a

于 2012-06-07T12:31:27.553 回答
2

当您通过ComplexWriter“接口”访问对象时,编译器将尝试将函数调用解析为Write(int)使用该类中的定义。如果它不能这样做,它将考虑基类。

在这种情况下,您有两个候选者:Write(any)和模板版本。由于此时没有明确Write(int)的可用选项,因此必须在这两个选项之间进行选择。 Write(any)需要隐式转换,而模板版本不需要,因此调用模板版本(依次调用Write(any))。

要使Write(int)fromWriter可用,请导入Writer::Write函数:

class ComplexWriter : public Writer
{
  using Writer::Write;
  // rest is as before
};
于 2012-06-07T12:48:01.730 回答