C++函数重载(理解为什么这种情况是模棱两可的)

3

我得了头痛感冒,可能是因为我太拥挤了而无法理解这里发生了什么,但我想不出以下内容为什么不能编译?

#include <string>
#include <iostream>

class Base {

public:
    virtual void foo(const std::string & data) {
        foo(data.data(), data.size());
    }
    virtual void foo(const void * bytes, int size) = 0;

};

class Derived : public Base{

public:
    virtual void foo(const void * bytes, int size) {
        std::cout << "Num Bytes: " << size << std::endl;
    }
};

int main() {
    Derived x;
    std::string blah = "Hello";
    x.foo(blah);
    return 0;
}

我收到的错误信息是:
./foo.cpp: In function ‘int main()’:
./foo.cpp:25:15: error: no matching function for call to ‘Derived::foo(std::__cxx11::string&)’
     x.foo(blah);
               ^
./foo.cpp:17:18: note: candidate: virtual void Derived::foo(const void*, int)
     virtual void foo(const void * bytes, int size) {
                  ^
./foo.cpp:17:18: note:   candidate expects 2 arguments, 1 provided

如果我将第一个 foo 实例重命名为 fooString,那么一切都正常了,所以似乎第二个 foo 实例在某种程度上隐藏了第一个实例。然而,考虑到第二个实例有两个参数而不是一个,我无法弄清它如何会产生歧义。
更新:如果没有继承(如果它都是一个类),它也可以正常工作,所以我怀疑我误解了一些继承规则。

3
为什么虚函数会被隐藏?当派生类定义了与基类中同名的函数时,该派生类函数将“隐藏”基类中的虚函数。如果您通过基类指针或引用调用该函数,则将调用派生类中的函数而不是基类中的虚函数。这种行为称为“函数隐藏”。在C++中,可以使用作用域解析运算符(::)来访问被隐藏的基类函数。例如,如果要从派生类中调用基类的虚函数,则可以使用以下语法:derived_object.base_class::function_name();这将直接调用基类中的虚函数,而不管派生类中是否重载了该函数。 - user2100815
@latedeveloper 谢谢,解释得很清楚。 - Pace
返回已经运作的文本:x.Base::foo(blah); - Jean-François Fabre
2个回答

2
您的Derived类中的virtual void foo(const void * bytes, int size)函数期望两个参数,但是当您从main中调用此函数x.foo(blah);时,您只传递了一个参数blah
您需要传入两个参数来调用该函数,因为您的Derived类中的foo函数期望两个参数。
或者,如果您想调用Base类的foo函数,请尝试x.Base::foo(blah);

1
您的代码问题不是函数模糊不清!相反,问题在于Derived中的覆盖实际上隐藏了基类函数!如果您想避免此隐藏,可以使用using声明使基类版本可用:
class Derived: public Base {
    // ...
public:
     using Base::foo;
     void foo(void const* bytes, int size) override {
        // ...
     }
};

或者你可以在调用的地方使用限定符显式调用基类函数:

x.Base::foo(blah);

为了避免派生类在覆盖虚函数时需要做特殊处理,最好采用将虚函数设为protected的方法,并使用公共函数代理调用这些虚函数(这种方法在标准C++库中一直被一致使用),例如:
class Base {
protected:
    virtual void do_foo(std::string const& s) {
        this->foo(s.c_str(), s.size());
    }
    virtual void do_foo(void const* bytes, int size) = 0;
public:
    void foo(std::string const& s) { this->do_foo(s); }
    void foo(void const* bytes, int size) { this->do_foo(bytes, size); }
};

然后在派生类中适当地覆盖 do_foo() 方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接