首页 > 试题广场 >

阅读如下程序,该程序的执行结果为?

[单选题]
阅读如下程序,该程序的执行结果为?
#include "stdio.h"
class A
{
public:
    virtual void Test()
    {
        printf("A test\n");
    }
};
class B: public A
{
public:
    void func()
    {
        Test();
    }
    virtual void Test()
    {
        printf("B test\n");
    }
};
class C: public B
{
public:
    virtual void Test()
    {
        printf("C test\n");
    }
};
int main()
{
    C c;
    ((B *)(&c))->func();
    ((B)c).func();
}


  • C test				
    B test
  • B test
    B test
  • B test			
    C test
  • A test
    C test
推荐
答案 A
解释:
(( *)(& c ))-> func (); 是多态行为
(( B ) c ). func (); 不是多态行为。
编辑于 2015-02-04 21:35:05 回复(3)
((     *)(&  c  ))->  func  ():引用传递,多态;
((  B  )  c  ).  func  (); 此时设计object slicing, 故不存在多态
发表于 2015-08-19 10:48:13 回复(1)
这道题目可以这么去拆分就很好理解了:
 ((B *)(&c))->func()   ==》   B *temp;   temp = &c;    temp->func();   ==》 这不就是一个典型的多态问题么,用基类指针指向派生类对象,所以肯定调用的是C对象的func函数,输出 C test

((B)c).func();   ==》 不涉及指针的操作,自然就没有多态行为的发生。
发表于 2015-07-04 09:50:50 回复(4)
答案选A,推荐的解析我觉得不对,应该是这么分析:((B *)(&c))->func();此句调用func,先分析func函数,该函数不是虚函数,自然不会是多态问题,所以不要往多态方面分析。指针是指向类C的对象c,此时尽管加了(B *),可是依然指向的是c的首地址,因此调用的是c中的func函数,而func中Test()之前省略了this指针,此时this当然是对象c,那也只能调用c中的成员函数Test(),所以输出C test。
((B)c).func(),此代码是先建立类B的对象c,然后调用c的成员函数func(),当然func中的Test()是属于类B的对象c的成员函数,自然会输出B test。
发表于 2016-01-14 20:02:58 回复(16)
查阅了各种资料,我来说一下我的看法吧:
(1)((B *)(&c))->func():编译阶段,系统发现B类型有一个非虚函数func,静态绑定,相当B::func((B *)(&c)),传入的this指针是B类型。在func内部调用this->Test(),由于Test是虚函数,动态绑定,通过虚函数表调用C::Test()。
(2)((B)c).func():强制类型转换发生对象切割,相当于用C初始化一个临时对象Btemp,vptr指向B的虚函数表,等价于Btemp.func()。根据静态绑定,调用B::func((B *)Btemp),在func内部调用this->Test(),Test是虚函数,动态绑定,通过虚函数表(注意此时的虚函数表是B)调用B::Test()。
发表于 2017-03-07 09:32:31 回复(6)
啥头像
第二个为什么是B test,是因为产生了切割

这是  向上造型  的两类,第一类是指针和引用,不产生切割,如本题的 ((B *)(&c))->func();;第二类是直接转换对象类型,会产生切割,如本题的((B)c).func();
产生切割时,把子类多余的不部分去除了,并把虚表指针vptr重新指向父类的虚函数表。因为vptr变了,所以输出B test

发表于 2016-05-16 13:31:53 回复(0)

相信:((B)c).func();这句大家都懂,无非就是静态调用嘛(要启用动态调用需要由基类的指针或引用来发起,而且调用的函数得是虚函数 );
既然调用前c对象被强制转换为B类型,那么调用的自然是B类中的对应函数了。
对于:((B *)(&c))->func(); 首先,func函数在类B中并不是虚函数,所以语句中调用的func是B类中的函数;其次,在func中调用了虚函数,
也就是此时发生了动态调用(调用func是是静态的),相当于在B类的func中发生了如下调用:((B *)(&c))->Test();满足动态调用的要求,调
用的是C类的test函数。
发表于 2016-08-19 10:46:40 回复(3)
C c;声明了一个C类的对象c。
((B *)(&c))->func(); 用B类的指针指向C类对象,此时func()是B类中的,由于Test()声明为虚函数,所以根据实际对象找到虚函数表,得到C中的虚函数输出"Ctest".
((B)c).func();
将c转化为B 类,(相当于把一个范围大的强制转化为范围小的如double 类型转化为int ),此时c不再是C类,而就是一个B 类的对象。



发表于 2016-05-22 15:16:59 回复(1)
看你们答案没说出个所以然。 区别是,只有指针才能实现多态,而对象的向上转换是单纯的类型转换+赋值,多态就无了
发表于 2023-07-14 08:41:10 回复(1)
class A
{
public:
    A() {
        printf("A construct\n"); 
    }
    virtual void Test()
    {
        printf("A test\n");
    }
};
class B: public A
{
public:
    B() : A() {
        printf("B construct\n");
    }
    void func()
    {
        printf("B func\n");
        this->Test();
    }
    virtual void Test()
    {
        printf("B test\n");
    }
};
class C: public B
{
public:
    C() : B() {
        printf("C construct\n");
    }     
    void func()
    {
        printf("C func\n");
        this->Test();
    }
    virtual void Test()
    {
        printf("C test\n");
    }
};
int main()
{
    C c;
    ((B *)(&c))->func();
    ((B)c).func();
    return 0;
}
\\Dev-C++ TDM-GCC 4.9.2 64-bit
\\Result:
\\A construct
\\B construct
\\C construct
\\B func
\\C test
\\B func
\\B test

1.首先定义了一个C的对象,而后强制通过B类指针访问C对象地址,构成动态绑定,但是访问的函数并非虚函数,所以根据静态类型来找函数即B类的func()【我在C类里重定义了func(),运行结果也佐证了我的想法】,而后调用Test()这个时候相当于this->Test(),this是一个B类指针动态绑定了C类对象c,Test()是一个虚函数,所以根据动态类型来找函数即C类Test()。
2.将对象c强制转换成B类型,并没有生成临时变量也没有构成动态绑定,此时调用func()成员函数即B类中的func(),func()调用Test(),this是一个B类指针绑定了B类对象c,调用B类Test()。

编辑于 2018-08-06 17:03:50 回复(0)
((B *)(&c))->func() 这条语句先取了c的地址然后转化为b类型指针,也就是,指针类型是b,对象类型是c。由于func不是虚函数,所以根据指针类型选择哪个func(c中有继承自b的func),也就是调用b中的func,然后又调用虚函数,这里在普通类成员函数中调用虚函数也可以实现多态(the c++ programing language 中2.5.5有讲到),所以调用c类中的虚函数,输出C test
发表于 2017-05-07 11:21:38 回复(0)
我觉得是由于是用B类指针指向C类对象,由于c对象继承了B类的所有函数,包括func函数,因此在执行时便会执行func函数,但由于此时的vptr指针仍然指向c,因此在执行虚函数test的时候,执行的是子类的test函数;
发表于 2020-11-22 10:30:31 回复(0)
((B *)(&c))->func()   ==》   B *temp;   temp = &c;    temp->func();   ==》 这不就是一个典型的多态问题么,用基类指针指向派生类对象,所以肯定调用的是C对象的func函数,输出 C test

((B)c).func();   ==》 不涉及指针的操作,自然就没有多态行为的发生。
发表于 2022-08-16 15:51:36 回复(0)
总的来说,该题没有用到虚函数,虽然使用了动态联编,但是使用的是成员函数func,所以只使用类中的方法,而且调用B类构造了暂时对象c,不和c类对象c冲突,最终调用B类的方法
发表于 2022-02-27 20:44:06 回复(0)
((B *)(&c))->func();基类指针指向子类的对象,当然是包含多态,如果虚函数被重写,则调用的是重新的函数
((B)c).func();不涉及到指针的操作,所以不涉及到多态,调用的是B的fun,B的test函数。
继承和派生可以这么理解,派生类肯定是要比基类大的,所以在赋值的时候基类肯定不能接受全部的子类对象。
发表于 2019-08-14 11:08:27 回复(0)

直接上图,直接用动态静态转换的时候vtable没变,肯定是c

但你用了(B) 在这里却进行了一次拷贝构造函数,又生成了B类的对象

编辑于 2018-09-12 17:43:46 回复(0)
mark
发表于 2018-06-27 16:55:48 回复(0)
只有通过基类的指针或引用调用虚函数时,才会发生动态绑定
发表于 2018-05-20 10:49:12 回复(0)
多态
发表于 2018-04-18 07:14:38 回复(0)
  ((B *)(&c))->func();中调用Test(),调用的格式为((B *)(&c))->Test();想清每次函数调用的this指针是谁,问题就迎刃而解了
编辑于 2018-03-26 16:59:59 回复(0)
1.    ((B *)(&c))->func();这里是把对象c的地址转换为类B的指针,然后指向func()函数,实现了多态。
 2.   ((B)c).func(); 这里是把对象c转换为类B的对象,然后调用func()函数,属于非多态。

赋值兼容规则:
在公有派生的情况下
①派生类的对象可以赋值为基类的对象
②派生类的对象可以初始化基类的引用
③派生类对象的地址可以赋值为基类的指针

编辑于 2018-03-19 10:00:11 回复(0)