首页 > 试题广场 >

下面程序的输出是?

[单选题]
下面程序的输出是()
class A
{
public:
    void foo()
    {
        printf("1");
    }
    virtual void fun()
    {
        printf("2");
    }
};
class B: public A
{
public:
    void foo()
    {
        printf("3");
    }
    void fun()
    {
        printf("4");
    }
};
int main(void)
{
    A a;
    B b;
    A *p = &a;
    p->foo();
    p->fun();
    p = &b;
    p->foo();
    p->fun();
    A *ptr = (A *)&b;
    ptr->foo();
        ptr->fun();
    return 0;
}
  • 121434
  • 121414
  • 121232
  • 123434
推荐
答案:B
1,首先声明为A类型的指针指向实际类型为A的对象,调用的肯定是A的方法,输出1 2,
2,然后声明为A类型的指针指向实际类型为B的对象,则非虚函数调用A的方法,输出1,虚函数调用实际类型B的方法,输出4
3,声明类型为A的指针指向实际类型为B的对象,进行一个强制类型转换,其实这种父类指针指向子类会自动进行类型转换,所以是否强制类型转换都不影响结构,原理同上一步,结果输出1 4
所以最终输出为121414
编辑于 2015-01-31 11:01:04 回复(8)
想问一下 foo函数不是隐藏吗
发表于 2016-09-17 11:16:05 回复(1)

B

发表于 2015-05-20 18:06:33 回复(0)
由于类A中fun()函数为虚函数,所以子类B中fun()函数也为虚函数,所以先调A中2个,结果为12.
接着由于foo()不为虚函数,所以调用父类中的foo()输出1,而B中fun()为虚函数,所以调用自身,输出4.最后类似同样为14
发表于 2015-05-12 16:25:08 回复(0)
大家都觉得很自然,但是没有注意到一个小插曲,就是这个foo()触发的隐藏机制: 派生类的foo()由于函数名,参数与基类都相同,然而又没有virtual修饰,因此不可避免地会触发隐藏。
(一旦有virtual修饰就成覆盖了!搞不清楚隐藏何时触发的同学请百度:重载、覆盖、隐藏的区别)

 问题是,看到有同学问: 为什么此处触发隐藏了,p和ptr在调用foo()的时候仍然调用基类的,不是被隐藏了么???
 这么问的原因是,很多同学知道了有隐藏这么回事,但是不清楚隐藏触发后会发生什么。 隐藏机制触发之后,指针的调用取决于指针的类型。如果定义的是派生类指针,则该基类成员不可见(隐藏),但是若为基类指针,该基类成员仍然是可见的啊!因为此处的p和ptr均为基类指针,只是分别指向了基类和派生类对象,所以调用foo()的时候仍然是基类的成员。
但是如果定义个派生类指针pb,如下:
 B *pb=&b;
 pb->foo(); 
这时只会调用派生类的foo(),虽然B继承自A,但是基类的foo()会被隐藏。 
这样看起来似乎莫名其妙,因为你想当然地认为派生类的指针肯定调用自己的成员啊,隐藏存在的意义是什么?就像此题,不用考虑它我也能做对!

但是一旦foo()里有参数的时候,你就会大吃一惊!
假设A中为void foo(float a),B中为void foo(int a): 
 做如下调用: 
B *pb=&b; 
pb->foo(3.14); 
到底会调用谁?你可能会想: 首先foo()成 员不是虚函数,但是B继承A,B中有两个foo(),调用foo(3.14)时根据参数类型应该匹配基类的void foo(float)成员。 
然而并不是!
因为触发了隐藏机制,基类的void foo(float)会被隐藏,所以即使你调用foo(3.14)仍然只会调用派生类的void foo(int)成员。 
你的惊讶正好解释了隐藏机制存在的意义。
(PS:牛客网上C/C++专项训练上有专门一道题考察这种情况,当时解释里提出隐藏机制时大多数人也是一脸懵逼)  

总结:
1.判断要点:如果不是重载也不是覆盖,派生类和基类中一旦出现同名函数,一定触发隐藏机制(这是个简便判断技巧,你可以考虑除去重载和覆盖的任何同名函数情况,一定满足隐藏机制触发的两条规则)。
2.隐藏触发的结果:指针对成员的函数调用取决于指针类型。
若本身是基类指针(不管指向基类还是派生类)则仍然调用基类成员(不会牵扯到派生类,此处是隐藏,和多态没关系,按第1点已说明隐藏的触发可以首先排除覆盖,也就是多态问题);
若本身是派生类指针,这时你就会看到隐藏的威力!此时不是简单地继承基类的成员,然后根据参数匹配调用,而是隐藏基类成员,只会调用派生类成员。
编辑于 2016-12-05 21:34:44 回复(13)
当定义基类指针指向子类对象时,通过这个指针调用子类和基类的同名函数时,基类定义为虚函数的话,就调用子类的这个函数,否则调用基类的这个函数
发表于 2015-09-04 20:24:19 回复(0)
父类指针指向子类时,子类会自动转换成父类的相应指针,强制类型转换也和实际默认的一样。
发表于 2016-05-24 21:32:44 回复(0)
《effective c++》 item_36  
对non-virtual函数的调用是静态绑定的(see Item 37)。
所以,类型是Base*的pb和类型是Derived*的pd,总是会调用定义指针时,所属类型中的那个方法。
即pb->func()调用Base::func,pd->func()调用的是Derived::func。

总结,通过指针调用非virtual函数,将执行声明指针时,你所使用的那个类型中的函数,与指针指向的对象无关,
发表于 2019-06-16 00:24:28 回复(0)
多态性考察问题,其实主要看指针类型和是否有虚函数!
发表于 2017-08-04 20:15:18 回复(0)
基类指针调用函数,如果函数在基类中是虚函数,则按照指针实际指向(指向基类?子类?)的类型调用函数;如果函数在基类中不是虚函数,则按指针本身(指针声明的类型)的类型调用函数
发表于 2016-04-15 10:04:31 回复(0)
转 1. C++中含有虚函数的类是可以实例化的,含有纯虚函数的类只能被继承,不能被实例化。 2. c++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。因此,在子类重新声明该虚函数时,可以加,也可以不加,但习惯上每一层声明函数时都加virtual,使程序更加清晰。 3. 派生类若函数名、参数与基类都相同,又没有virtual修饰,会触发隐藏。 触发隐藏后,指针的方法调用只取决于指针类型,基类指针调用基类该方法,子类指针调用子类该方法
发表于 2022-06-08 20:03:11 回复(0)
1214
编辑于 2021-12-05 20:48:54 回复(0)
个人理解,谁家指针就是调用谁家的方法,感觉跟强行转换或者指向没有关系;若碰到自家被调用的是虚函数,那么就是调用到子类对应的方法~
发表于 2021-04-08 16:58:13 回复(0)
只有fun()函数是虚函数,foo()不是虚函数
发表于 2021-03-29 14:43:19 回复(0)
1. C++中含有虚函数的类是可以实例化的,含有纯虚函数的类只能被继承,不能被实例化。 2. c++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。因此,在子类重新声明该虚函数时,可以加,也可以不加,但习惯上每一层声明函数时都加virtual,使程序更加清晰。 3. 派生类若函数名、参数与基类都相同,又没有virtual修饰,会触发隐藏。 触发隐藏后,指针的方法调用只取决于指针类型,基类指针调用基类该方法,子类指针调用子类该方法
编辑于 2020-08-09 03:29:47 回复(0)

强制转换与否不影响这种指向子类的指针的结果

发表于 2020-03-05 19:17:00 回复(0)
C++Primer Plus 493
发表于 2019-09-01 10:26:01 回复(0)
C++Primer Plus(第6版):P493
有这样一句话:如果方法是通过引用或者指针而不是对象来调用的,调用规制如下:
1.如果没有使用关键字virtul,程序将根据引用类型或者指针类型选择方法;
2.如果使用了关键字virtual,程序将根据引用或者指针指向的对象的类型来选择方法
发表于 2018-10-28 15:50:08 回复(0)
java程序猿做这些题 真的很费劲 我以为还会有多态什么的
发表于 2017-04-19 11:12:08 回复(0)
B
学了点
发表于 2015-04-09 13:59:17 回复(0)
B
p = &b;
p->foo(); P是基类A的指针 
p->fun();动态编联

发表于 2015-04-07 18:27:24 回复(0)