7

我正在研究 C++。以下是我的代码:

#include <iostream>
using namespace std;
class base
{
        public:
        virtual void display(int a = 4)
        {
                cout << "base ::  "<<  a*a << endl;
        }
};

class derived : public base
{
        public:
        void display(int b = 5)
        {
                cout << " Derived :: " << b*b*b <<  endl;
        }
};

int main()
{
        base *bobj;
        derived dobj;
        bobj = &dobj;
        bobj->display();
        return 0;
}

输出是:

Derived :: 64

基类的函数被调用,但使用派生函数的参数的默认值。为什么派生类方法 display() 采用基类方法参数值?

4

5 回答 5

7

因为您是通过指向base. 这就是它的工作原理。

在实际调用之前,参数被压入参数堆栈(或内部寄存器) 。因为你有一个指向的指针base并且没有参数,所以默认值4被传递给函数。然后调用正确的函数 ( derived::display),但使用base的默认参数。当然,这是一个实现细节,但行为是标准的。

C++03 8.4/10

虚函数调用 (10.3) 在虚函数的声明中使用默认参数,由表示对象的指针或引用的静态类型确定。派生类中的覆盖函数不会从它覆盖的函数中获取默认参数。

我会强调引用,但整个事情是不言自明的。

dobj.display();

将打印125(5^3)。

于 2012-09-03T09:16:24.373 回答
2

默认参数由调用者插入。您的代码相当于

class base {
public:
    virtual void display(int a) { cout << "base ::  "<<  a*a << endl; }
    inline void display(void) { display(4); }
};

等等

通过base指针调用时,将插入基类的默认值。

于 2012-09-03T09:19:30.870 回答
2

标准说明了一切:

(§8.3.6/10) 虚函数调用 (10.3) 在虚函数的声明中使用默认参数,由表示对象的指针或引用的静态类型确定。派生类中的覆盖函数不会从它覆盖的函数中获取默认参数。[ 例子:

    struct A {
      virtual void f(int a = 7);
    };
    struct B : public A {
      void f(int a);
    };
    void m() {
      B* pb = new B;
      A* pa = pb;
      pa->f();   // OK, calls pa->B::f(7)
      pb->f();   // error: wrong number of arguments for B::f()
    }
    — end example ]
于 2012-09-03T09:22:09.663 回答
0

让自己成为一个不那么做作的测试设置,它变得很清楚:

#include "base.hpp"

int compute(base * p)
{
    return p->display();
}

现在有两点很明显:

  1. 默认参数只能来自 中指定的默认参数base

  2. 实际调度是动态的,因为display它是一个虚拟成员函数。

于 2012-09-03T09:29:58.543 回答
0

当您使用->即使用指针调用函数时,它使用被指向的对象来做出决定,在这种情况下是Derived类的对象。

正如规范所说...

虚函数调用使用虚函数声明中的默认参数,由表示对象的指针或引用的静态类型确定。派生类中的覆盖函数不会从它覆盖的函数中获取默认参数。

于 2012-09-03T09:20:55.420 回答