为什么C++更喜欢这个模板方法而不是方法重载

Why does C++ prefer this template method to a method overload?

本文关键字:方法 重载 模板方法 C++ 更喜欢 为什么      更新时间:2023-10-16

假设我有两个类,第一个用于编写基元类型(boolintfloat等),第二个扩展第一个类以编写复杂类型:

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);
}

当我在 ComplexWriter 类中声明 Write(int) 方法时,行为也会突然改变(请参阅第一个代码段中注释掉的行)。然后,它将Wrote an int打印到控制台。

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

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

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

当您将虚拟重载添加到 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

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

在本例中,您有两个候选项:Write(any) 和模板化版本。 由于此时没有明确的Write(int)可用,因此必须在这两个选项之间进行选择。 Write(any)需要隐式转换,而模板化版本不需要,因此调用模板化版本(反过来调用Write(any))。

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

class ComplexWriter : public Writer
{
  using Writer::Write;
  // rest is as before
};