首页 > 试题广场 >

阅读程序,给出最终的输出结果。​

[单选题]
using namespace std;
class Base
{
    int x;
    public:
        Base(int b): x(b) {}
        virtual void display()
        {
            cout << x << endl;
        }
};
class Derived: public Base
{
    int y;
    public:
        Derived(int d): Base(d), y(d) {}
        void display()
        {
            cout << y << endl;
        }
};
int main()
{
    Base b(2);
    Derived d(3);
    b.display();
    d.display();
    Base *p = &d;
    p->display();
    system("pause");
    return 0;
}
上面程序的输出结果是什么?
  • 2 2 3
  • 3 2 2
  • 2 3 3
  • 2 3 2
基类与派生类中的virtual方法:
如果方法是通过引用或指针而不是对象引用的,将确定使用哪种方法,参考如下:
  • 如果没有使用virtual,根据引用或指针类型选择方法;
  • 如果使用了virtual,根据引用或指针指向对象的类型来选择方法。
这里 Base *p = &d;  基类型Base的display方法使用了virtual关键词,则根据指针指向对象的类型选择方法,指针指向对象类型为Derived,因此调用派生类Derived的display方法。

发表于 2018-11-12 09:34:45 回复(0)
更多回答
推荐
b.display(), 调用Base类的display函数,故第一个输出2;
d.display(), 调用Derived类的display函数,故第二个输出3;
p->display(), 由于基类指针指向派生类,display是虚函数,所以基类指针指向派生类的display函数,所以第三个输出3。

故选C
编辑于 2014-12-30 21:14:46 回复(1)
函数前有virtual修改程序会进行动态绑定,即在运行时确定调用哪个函数,c++内部是使用虚函数实现的。所以Base *p=&d 是典型的基类指针指向派生类对象,在调用的时候是派生类函数
发表于 2016-05-16 19:28:36 回复(0)
这里纯粹考虑调用就行了 ,别考虑虚函数动态绑定
发表于 2021-04-17 16:06:46 回复(0)

答案:C。

在面向对象中,多态指的是使用相同的函数名来访问函数不同的实现方法,
即“一种接口,多种方法”,用相同的形式访问一组通用的运算,
每个运算可能对应的行为不同。C++语言支持编译时多态和运行时多态,
其中,编译时多态指的是系统在编译时能确定调用哪个函数,
它具有执行速度快的优点,运算符重载和函数重载就是编译时多态。
运行时多态指的是系统在运行时动态决定调用哪个函数,
它为系统提供了灵活和高度问题抽象的优点,通过继承和虚函数实现运行时多态。
运行时多态的基础是基类指针,基类指针可以指向任何派生类对象。
在基类中的某成员函数被声明为虚函数后,在之后的派生类中可以被重新定义。
但在定义时,其函数原型,包括返回类型、函数名、参数个数和参数类型的顺序,
都必须与基类中的原型完全相同。只要在基类中显式声明了虚函数,
那么在之后的派生类中就不需要用关键字virtual来显式声明了,可以略去,
因为系统会根据其是否和基类中虚函数原型完全相同来判断是不是虚函数。
所以,派生类中的虚函数如果不显式声明也还是虚函数。

对于虚函数,有几点内容需要引起读者注意:

1)因为虚函数使用的基础是赋值兼容
(赋值兼容是指在需要用到基类对象的任何地方都可以用公有派生类的对象来代替),
而赋值兼容成立的条件是派生类从基类public继承而来。所以,当使用虚函数时,
派生类必须是基类public派生的。
2)定义虚函数时,不一定要在最高层的类中,
而是看在需要动态多态性的几个层次中的最高层类中声明虚函数。

3)只有通过基类指针来访问虚函数才能实现运行时多态的特性。

4)一个虚函数无论被公有继承了多少次,它仍然是虚函数。

5)虚函数必须是所在类的成员函数,而不能是友元函数,也不能是静态成员函数。
因为虚函数调用要靠特定的对象类决定该激活哪一个函数。
6)内联(inline)函数不能是虚函数,因为内联函数是不能在运行中动态确定其位置的,
即使虚函数在类内部定义,编译时将其看作非内联。

7)构造函数不能是虚函数,但析构函数可以是虚函数。

本题中,Base b(2)定义了一个父类的对象b,
语句b.display()会调用Base的display方法输出2。
而d的类型为Derived,因此,语句d.display()会调用Derived的display方法输出3。
虽然p是指向Derived类型的指针,但它实际上指向的是子类的对象,
因此,p->display()函数调用的是派生类的display()函数(多态),输出为3。
所以,选项C正确。

编辑于 2018-07-13 17:00:55 回复(3)
即使不把基类的display声明为虚函数,输出也会是233;
 Derived(intd): Base(d), y(d) {} 此构造函数把基类成员赋值为3;
Base b(2)与动态绑定没有关系。
发表于 2015-04-07 16:32:20 回复(3)
基类指向派生类对象
发表于 2023-03-27 00:35:13 回复(0)
b.display(), 调用Base类的display函数,故第一个输出2;
d.display(), 调用Derived类的display函数,故第二个输出3;
p->display(), 由于基类指针指向派生类,display是虚函数,所以基类指针指向派生类的display函数,所以第三个输出3。
发表于 2021-11-15 16:25:17 回复(0)
b.display();毋庸置疑是Base类实例化调用该类函数,d.display();也是一样。Base *p = &d;注意是&d,所以基类的指针还是指向的是具体的派生类,这个其实是虚函数的向上转型以及动态绑定。
发表于 2020-09-11 10:36:44 回复(0)
有没有大佬可以帮忙解释一下Base(int b): x(b) {}  这句是啥意思。。。
我知道是构造函数,但是那个x(b)到底啥意思啊啊啊
卑微菜鸟在线求解答
ball ball大佬看看我
哭泣
发表于 2019-09-21 14:17:32 回复(2)
基类指针指向派生类
发表于 2019-02-23 21:20:58 回复(0)
觉得这道题有问题,base *p = &d;之后可以知道p实际指向的是派生类Derived的对象,因为它的基类有虚函数,那么会生成一张无覆盖的虚函数表,p->display()应该调用的是基类的display()函数呀
发表于 2017-10-03 14:52:39 回复(0)
指针,对象有区别
发表于 2017-04-11 11:35:52 回复(0)
子类继承基类,虽然子类构造函数调用了基类构造函数进行初始化,但是初始化的是子类内存模型中的继承自基类的成员(注意该数据成员为私有),而基类内存模型没有改变。
发表于 2017-03-02 11:37:10 回复(0)