1

请看下面的简单代码:

class A
{
public:
    A() {}
    virtual bool cmp(const A& a) const {cout << "cmp A" << endl; return true;}
};
class B : public A
{
public:
    B() {}
    ~B() {}
    bool cmp(const B& b) const {cout << "cmp B" << endl; return false;;}
};


int main()
{

    A a1;
    A a2;
    B b1;
    B b2;

    a1.cmp(a2); // as expected
    b1.cmp(b2); // as expected

    a1.cmp(b1); // upcasting
    // b2.cmp(a2); // conversion needed


    // Here is the problematic part:
    A* pa;
    pa = new B;

    pa -> cmp (b1); // Why why why the cmp of A runs?

    return 0;
}

我只是无法理解它 - 有 vptr 和 vtbl 以及一个与调用完全匹配的函数,没有任何强制转换。那么为什么调用 A 类的 cmp 呢?

任何合乎逻辑的答案将不胜感激。

4

7 回答 7

3

因为您没有覆盖操作员。您的课程中有 2 个不同的运算符。

要覆盖方法或运算符,签名必须完美匹配。这意味着:

  • 姓名
  • 参数
  • cv 限定词

基类运算符采用 aconst A&作为参数,派生类采用const B&.

于 2012-08-24T14:06:20.060 回答
1

因为A::cmpB::cmp签名不匹配。

b1首先转换为const A &并被A::cmp称为

于 2012-08-24T14:07:01.910 回答
1

你有两个覆盖

A::cmp(const A&)
B::cmp(const B&)

因此,当您这样做时,pa->cmp()它会调用A::cmp,因为 pa 的类型在编译时是 A 。这里没有 vptr 的意义,因为你根本没有覆盖任何东西。

它将是压倒一切的,如果你有

bool B::cmp(const A& b)

覆盖签名A::cmp(const A& b)

于 2012-08-24T14:07:14.233 回答
0

您在 B 上的方法是“隐藏”基类方法,因此您无法通过 B 看到它。有关更详细的说明,请参阅C++ FAQ 。

于 2012-08-24T14:10:33.673 回答
0

嗯,这是意料之中的,因为bool cmp(const B& b) const不会覆盖基类的虚方法,因为它们具有不同的签名。

于 2012-08-24T14:07:45.047 回答
0

因为B::cmp()签名不同于A::cmp(). 所以B::cmp()不是覆盖A::cmp(),而是隐藏它,它不是虚拟的,也不是通过调用知道的A*

于 2012-08-24T14:08:13.943 回答
0

请注意,虽然重载虚函数中允许使用协变返回类型,但不允许使用协变参数类型!所以你隐藏了基本的虚函数,而不是覆盖它。

于 2012-08-24T14:17:49.527 回答