在C ++类中同时覆盖和重载方法

时间:2015-01-30 11:15:12

标签: c++

考虑以下代码片段:

#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会给我一个编译错误说:

    $ 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&amp; username)的名称更改为B :: greetUser(const std :: string&amp; username),那么一切都按预期工作我明白了:

$ ./InheritanceTest 
Greetings, User!
Hello from C

这是否意味着不能同时在C ++类层次结构中重载和覆盖方法?为什么会这样?有没有合理的理由说明编译器无法明确地解析两个重载的函数原型,并根据需要覆盖相应的原型?

2 个答案:

答案 0 :(得分:2)

作为这个答案的前言,你所做的事情很少是一个好主意,因为这些函数具有不同的语义,不应该有相同的名称。

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

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使用哪个版本,因此遵循虚拟功能正确。

答案 1 :(得分:1)

使用:

static_cast<A const*>(this)->saySomething();

您还可以使用指向成员函数的指针:

(this->*(&A::saySomething))();