考虑以下代码片段:

#include <iostream>

class A
{
public:
    virtual ~A(){}
    virtual void saySomething() const
    {
        std::cout << "Hello from A" << std::endl;
    }
};

class B : public A
{
public:
    virtual ~B(){}
    virtual void saySomething(const std::string& username) const
    {
        std::cout << "Greetings, " << username << "!" << std::endl;
        saySomething();
    }
};

class C : public B
{
public:
    virtual ~C(){}
    void saySomething() const
    {
        std::cout << "Hello from C" << std::endl;
    }
};

int main()
{
    C* politeC = new C;
    B* politeB = dynamic_cast<B*>(politeC);
    politeB->saySomething("User");

    return 0;
}

铛会给我一个编译器错误,说:
    $ clang inheritanceTest.cpp -o InheritanceTestinheritanceTest.cpp:20:9: error: too few arguments to function call, expected 1,
      have 0; did you mean 'A::saySomething'?
        saySomething();
        ^~~~~~~~~~~~
        A::saySomething
        inheritanceTest.cpp:7:18: note: 'A::saySomething' declared here
        virtual void saySomething()
                 ^
        1 error generated.

但是,如果我确实说了A::saySomething(),那么在C中对saySomething()的重写将被完全忽略。程序打印输出:
$ ./InheritanceTest
Greetings, User!
Hello from A

奇怪的是,如果我只是将B::saySomething(const std::string&username)的名称更改为B::greetUser(const std::string&username),那么一切都会按预期进行,我得到:
$ ./InheritanceTest
Greetings, User!
Hello from C

这是否意味着不能同时重载和重写C++类层次结构中的方法?为什么会这样呢?有任何逻辑上的原因,为什么编译器无法明确解析两个重载的函数原型(prototype),并在必要时覆盖相应的原型(prototype)?

最佳答案

作为该答案的序言,您所做的很少是个好主意,因为这些函数具有不同的语义,并且不应具有相同的名称。

就是说,您遇到的问题是,基类中的函数名被派生类中的函数名覆盖。为了解决此问题,您需要像这样公开它们:

class B : public A
{
public:
    using A::saySomething; //HERE expose the function
    virtual void saySomething(const std::string& username) const;
    {
        //the compiler now knows to look in the base class for this function
        saySomething();
    }
};

class C : public B
{
public:
    using B::saySomething; //and HERE
    void saySomething() const;
};

现在,可以使用saySomething的所有版本来调用C实例。此外,将C*转换为B*将正确地从C::saySomething调用B::saySomething,因为您没有明确告诉B使用哪个版本,因此它正确地遵循了虚函数。

10-04 21:16