【问题标题】:Simulatenously Overriding and Overloading Methods in C++ Classes在 C++ 类中同时覆盖和重载方法
【发布时间】:2015-01-30 11:15:11
【问题描述】:

考虑下面的sn-p代码:

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

$ ./InheritanceTest 
Greetings, User!
Hello from C

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

【问题讨论】:

  • 你可以在saySomething()后面加上override,然后编译器会检查它是否真的是覆盖。

标签: c++


【解决方案1】:

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

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

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* 将正确地从B::saySomething 调用C::saySomething,因为您没有明确告诉B 要使用哪个版本,因此它正确地遵循虚函数。

【讨论】:

    【解决方案2】:

    用途:

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

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

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

    【讨论】:

    • 我赞成这个答案,因为它确实很有用。然而,问题更多的是为什么会发生这种情况,而不是如何解决它。因此,我不接受这个作为答案。
    • @MikeSeymour A::saySomething() 给出的结果与 (this->*(&A::saySomething))();似乎在前者中,函数在编译时被解析,但在后者中,由于使用函数指针间接,解析导致在运行时解析为 C::saySomething()
    • @balajeerc:对不起,我误读了这个问题。你是对的,但几句话的解释可能是一个更好的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    相关资源
    最近更新 更多