首页 > 试题广场 >

下面代码的输出为?

[单选题]
有如下C++代码:
struct A{
  void foo(){printf("foo");}
  virtual void bar(){printf("bar");}
  A(){bar();}
};
struct B:A{
  void foo(){printf("b_foo");}
  void bar(){printf("b_bar");}
};
那么
A *p = new B;
p->foo();
p->bar();
输出为:
  • barfoob_bar
  • foobarb_bar
  • barfoob_foo
  • foobarb_fpp
推荐
【正确答案】A
【解析】A * p = new B; // A 的指针指向 B 的对象。
当执行 new B 时,调用 B 的无参构造函数,由于 B 继承 A,所以先调用 A 的构造函数,在 A 的构造函数中调用了虚函数 bar(),这时调用的是 A 的 bar()。如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数本人类型定义的版本,因为在构造子类的时候,首先回去调用父类的默认构造函数,此时子类还是未初始化的,所以不可能调用子类函数;
p->foo(); 因为 foo() 不是虚函数,所以执行的是 A 的 foo();
p->bar(); 因为 bar() 是虚函数,所以执行的是 B 的 bar()。
 
静态联编和动态联编知识点讲解】
更多C++基础专业知识讲解,点击链接即可查看
https://www.nowcoder.com/link/zxyl-cpp89
编辑于 2021-11-18 08:39:36 回复(0)
Ze头像 Ze
A *p=newB;// A类指针指向一个实例化对象B, B类继承A类,先调用父类的无参构造函数,bar()输出bar,B类没有自己显示定义的构造函数。
p->foo();//执行B类里的foo()函数,因为foo不是虚函数,所以直接调用父类的foo函数,输出foo
p->bar();//执行B类的bar()函数, 该函数为虚函数,调用子类的实现,输出b_bar
编辑于 2015-09-06 10:48:49 回复(5)
答案是A,
一般不建议在构造函数或者析构函数中调用虚函数,因为在构造函数和析构函数中调用虚函数不会呈现多态性,也就是说在构造基类构造函数的时候,派生类的部分还没有构造,怎么谈去用虚函数实现动态绑定派生生类对象呢,所以构造B基类部分的时候,调用的基类的函数bar
对于foo函数不是虚函数不会有动态绑定,所以调用的基类部分
对于第三个bar调用,是虚函数,实现动态绑定,所以调用的是派生类部分
发表于 2015-09-06 11:21:52 回复(3)
1.只有用virtual修饰的函数才能动态绑定
2.如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数本人类型定义的版本(c++prime 中文版第四版 p497)
因为在构造子类的时候,首先回去调用父类的默认构造函数,此时子类还是未初始化的,所以不可能调用子类函数
发表于 2015-09-06 10:19:01 回复(1)
virtual 只能出现在类中,代表虚函数的意思。java中多态替代了这个功能,扯远了有点。
回归本题。virtual 标识bar()这个函数是虚函数,也就是打开了可以扩展使用子类函数的功能,实现了类的多态。
A *p=new B;
B继承A,所以先进行A的构造函数   =======输出bar
p->foo()  执行A类中的foo函数。==========输出foo
p->bar() 这里特别了,因为将B的值赋值A,所以,p满足多态前提条件,然后bar是虚函数,执行B中的
=========输出b_bar
 
发表于 2015-10-11 21:57:44 回复(2)
A *p=new B; // A类指针指向一个实例化对象B, B类继承自A类,先调用A类的无参构造函数,bar()输出bar,再调用B类的默认构造函数。(注:根据深度探索C++对象模型中的构造函数语意学,这里派生类B有一个带有默认构造函数的Base class,因此编译器必须为没有申明构造函数的B类合成一个默认构造函数!)
p->foo(); //执行B类里的foo()函数,因为foo不是虚函数,采用静态联编,所以直接调用父类的foo函数,输出foo;
p->bar();//执行B类的bar()函数, 该函数为虚函数,采用动态联编,调用子类的实现,输出b_bar。

编辑于 2016-07-29 13:56:56 回复(0)
A *p=newB;
本来,基类指针p是用来指向基类对象的,如果用它来指向派生类对象,则进行指针类型转换
——将派生类B对象的指针先转换为基类A对象的指针,然后再赋给p;
所以基类指针p指向的不是派生类,而是派生类对象中的基类部分,已经转化为基类了!
当然,无法使用基类指针取调用派生类对象中的成员函数,所以p->foo();调用的是基类的函数!
~
虚函数突破了这一限制,在派生类的基类部分中,派生类的虚函数取代了基类原来的虚函数,
因此使用基类指针调用派生类对象后,调用虚函数时就调用了派生类的虚函数。
~
总之:
1. 首先,必须要有指针引领,p->f(),而且这个指针一定是由基类定义的;
2. 把基类定义的指针指向派生类,这是一个强制类型转换的过程,把派生类强制转化为基类,所以这个时候调用函数,肯定调用的还是基类的;
3. 虚函数的功能就是,用派生类的函数替代同名基类的虚函数,这个时候再进行强制类型转换,保留的函数就是派生类的。
编辑于 2018-03-07 08:41:01 回复(0)
本题主要考查虚函数,构造函数不能是虚函数,当构造函数调用虚函数时并不会出现多态。类的其他成员函数设置成虚函数时,会覆盖父类的同名虚函数,只有子类被调用。
发表于 2017-04-21 08:24:16 回复(0)
在构造函数和虚函数中调用虚函数不会发生多态
发表于 2015-09-08 22:41:27 回复(0)
由继承关系,先调用A类的构造函数。
p->foo();//执行基类A类里的foo()函数,因为foo不是虚函数,所以直接调用父类的foo函数,输出foo
p->bar();//执行B类的bar()函数, 该函数为虚函数,调用子类的函数,输出b_bar
发表于 2015-09-07 12:08:39 回复(0)
子类首先调用父类构造函数,构造父类部分,此时虚函数机制及动态绑定尚未起作用,构造完成之前,在对象的内存模型当中,首地址的虚函数表指针,以及虚函数表都还尚未完全确定。此时说动态绑定没什么意义的。所以构造函数内的bar()只能是类内bar()函数。
对于p->foo()而言,由于p的静态类型是指向A的指针,所以根据函数调用查找规则,只能从当前作用域向上查找,于是乎输出"foo" 对于p->bar()就没什么疑问,调用派生类的bar() 输出"b_bar"。
发表于 2015-09-06 16:22:51 回复(0)
在这段代码中,当执行 A *p = new B; 时,发生了多态性。尽管 p 的静态类型是 A*,但动态类型是 B。因此,当调用 p->foo() 时,由于 foo 不是虚函数,所以会根据指针的静态类型 A* 调用 A 类中的 foo 函数,输出为 "foo";而调用 p->bar() 时,由于 bar 是虚函数,会根据动态类型 B 调用 B 类中的 bar 函数,输出为 "b_bar"。
发表于 2023-11-07 09:39:00 回复(0)
这道题,考察的就是多态。
多态的条件:1、有继承关系。2、父类有虚函数、3、子类重写父类同名的虚函数。
显然:
1、该题中foo只满足1、3点,所以foo不会发生多态。当父类指针指向子类对象时,父类对象调用父类的函数。
2、该题中bar满足多态的条件,所以会发生多态。当父类指针指向子类对象时,父类对象会调用子类中的发生多态的函数。
编辑于 2023-05-01 10:22:50 回复(0)
p->foo(); 因为 foo() 不是虚函数,所以执行的是 A 的 foo();
p->bar(); 因为 bar() 是虚函数,所以执行的是 B 的 bar()。
发表于 2024-03-21 20:11:58 回复(0)
首先,创建一个指向子类B的父类指针p,这是多态的一种典型用法。然后调用p的两个成员函数foo和bar,分别输出"foo"和"bar"。 由于A中的构造函数调用了bar(),因此在创建B对象时先调用A的构造函数,在A的构造函数中又调用了虚函数bar(),但此时对象还没有完全构造完成,因此调用的是A中的bar()。所以先输出了"bar"。接下来,p指向了B对象,并且通过指针p调用B中的成员函数foo()和bar()。 在C++中,当派生类重定义基类中的非虚函数时,在派生类中定义新版本后就无法直接访问基类版本的该函数。因此,当执行p->foo()时,会去寻找父类A中对应的函数foo(),而不是子类B中重写/隐藏了父类A中同名非虚函数。 而对于虚函数bar()而言,在父类A中已经声明为虚函数,在子类B中被重写,并且通过多态性实现动态绑定。所以执行p->bar()时会根据实际对象类型确定要调用哪一个版本的虚函数,在这里即为B::bar()。从而输出"foob_bar"。
发表于 2023-04-25 16:51:50 回复(0)
//构造父类时调用virtual void bar(){printf("bar");},打印bar
A *p = new B;

//foo()不是虚函数,应该调用父类的foo()
p->foo();
//bar()是虚函数,调用子类的b_bar()
p->bar();
发表于 2022-03-10 11:39:23 回复(0)
b继承a 类,首先调用a类的构造器,然后执行p-foo,再调用父类的foo方法。
发表于 2022-01-13 23:53:49 回复(0)
我没看错的话,这是结构体吧?是类吗
发表于 2021-10-23 19:15:27 回复(0)
那我想调用B的foo该怎么办
发表于 2020-02-24 19:52:17 回复(1)
眼瞎了,没看到构造函数
发表于 2019-08-16 23:43:14 回复(0)
在实例化对象的时候,如果实例化的是一个派生类的对象,要先调用父类的构造函数,再调用子类的构造函数,同时实例化两个对象,这样可以拼接成一个对象,完整的子类对象
发表于 2019-04-24 20:28:24 回复(0)