首页 > 试题广场 >

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

[单选题]
如下程序:
#include "stdio.h"
class Base
{
public:
    Base()
    {
        Init();
    }
    virtual void Init()
    {
        printf("Base Init\n");
    }
    void func()
    {
        printf("Base func\n");
    }
};
class Derived: public Base
{
public:
    virtual void Init()
    {
        printf("Derived Init\n");
    }
    void func()
    {
        printf("Derived func\n");
    }
};

int main()
{
    Derived d;
    ((Base *)&d)->func();
    
    return 0;
}
该程序的执行结果
  • Base Init				
    Derived func
  • Base Init
    Base func
  • Derived Init			
    Base func
  • Derived Init
    Derived func
在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。
在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
发表于 2015-07-18 21:45:30 回复(10)
Derived d;首先创建对象d,找到基类的构造函数Base(){Init();},此时需要调用Init()函数,不要被virtual迷惑,这只是普通的调用函数,虚函数不起作用,所以调用的还是基类的Init(),输出Base Init;
((Base *)&d)->func(),虽然是动态联编,但是func()不是虚函数,Base*指针指向派生类不起作用,执行的是基类的func(),输出Base func;

故选 B
编辑于 2015-10-05 21:59:05 回复(4)
要明确一点,在构造函数执行完以后虚函数表才能正确初始化,所以在构造函数中调用虚函数时此时虚函数表还没有被正确初始化,调用的是本类的函数,即静态类型所对应的函数,同理在析构函数中也不能调用虚函数,因为此时虚函数表已经被销毁
发表于 2016-09-11 12:21:22 回复(0)
基类构造函数中调用虚函数不会发生多态。 因为初始化一个子类对象时,首先调用基类的构造函数,此时子类的成员还没有初始化,如果基类
中有虚函数,编译器是不会去调用含有没有初始化的子类中的虚函数的



发表于 2017-07-27 22:03:02 回复(4)
来自@flywith
        在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现
        在析构函数中也不要调用虚函数在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
编辑于 2017-06-14 19:49:14 回复(0)
1.创建派生类对象时,程序首先创建基类对象。基类对象应当在程序进入派生类构造函数之前被创建。
2. 虚方法:如果没有使用关键字virtual,程序将根据引用类型或者指针类型来选择方法;如果使用了virtual,程序将根据引用或者指针指向的对象的类型来选择方法。
发表于 2016-07-25 10:37:03 回复(0)
当派生类对象生成的时候会调用构造函数,首先调用基类的构造函数生成基类部分,然后调用自己的构造函数,析构的时候顺序正好相反,先析构自身的然后析构释放派生类的
发表于 2015-05-04 09:38:35 回复(1)
在构造函数不要调用虚函数。 在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。 Derived d;首先创建对象d,找到基类的构造函数Base(){Init();},此时需要调用Init()函数,不要被virtual迷惑, 这只是普通的调用函数,虚函数不起作用,因为子类还没有开始构造,所以调用的还是基类的Init(), 输出Base Init; ((Base*)&d)->func(),虽然是动态联编,但是func()不是虚函数,Base*指针指向派生类不起作用,执行的是基类的func(), 输出Base func; 在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的 可能double free
发表于 2021-10-19 12:07:55 回复(0)
  在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)。——P52《Effective C++》
发表于 2020-05-19 09:34:29 回复(0)

在构造派生类对象时,首先调用基类构造函数初始化对象的基类部分,再调用派生类构造函数。在执行基类构造函数时,对象的派生类部分是未初始化的。实际上,此时的对象还不是一个派生类对象(不完整)。

析构派生类对象时,首先调用的是派生类析构函数,一旦开始执行派生类析构函数,对象内派生类的成员变量便呈现未定义值,此时对象便不完整。 
 
为了适应这种不完整,编译器将对象的类型视为在调用构造/析构函数时发生了变换,即:视对象的类型为当前构造函数/析构函数所在的类的类型。由此造成的结果是:在基类构造函数或者析构函数中,会将派生类对象当做基类类型对象对待。而这样一个结果,会对构造函数、析构函数调用期间调用的虚函数类型的动态绑定对象产生影响,最终的结果是:如果在构造函数或者析构函数中调用虚函数,运行的都将是为构造函数或者析构函数自身类类型定义的虚函数版本。

发表于 2018-06-22 11:31:24 回复(1)
插个眼,普通调用,virtual不会跳转到子类的~
发表于 2021-03-27 18:02:28 回复(0)
妈的,func不是虚函数,自以为是了。
发表于 2021-01-05 01:37:43 回复(0)
1. 子类Derived中并没有定义构造函数,因此在执行Derived d语句的时候会掉用基类中的构造函数,因此输出 Base Init
2.基类中的voidfunc()函数并没有定义成 virtual voidfunc() = 0;的形式,因此,((Base *)&d)即基类对象的指针所调用的func为基类中的func
发表于 2016-03-25 13:33:12 回复(0)
编译时若基类中有虚函数,编译器为该的类创建一个一维数组的虚表,存放是每个虚函数的地址。基类和派生类都包含虚函数时,这两个类都建立一个虚表。构造函数中进行虚表的创建和虚表指针的初始化。在构造子类对象时,要先调用父类的构造函数,初始化父类对象的虚表指针,该虚表指针指向父类的虚表。执行子类的构造函数时,子类对象的虚表指针被初始化,指向自身的虚表。每一个类都有虚表。虚表可以继承,如果子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现。派生类的虚表中虚函数地址的排列顺序和基类的虚表中虚函数地址排列顺序相同。当用一个指针/引用调用一个函数的时候,被调用的函数是取决于这个指针/引用的类型。即如果这个指针/引用是基类对象的指针/引用就调用基类的方法;如果指针/引用是派生类对象的指针/引用就调用派生类的方法,当然如果派生类中没有此方法,就会向上到基类里面去寻找相应的方法。这些调用在编译阶段就确定了。
发表于 2024-07-26 15:55:10 回复(0)
有这么写代码的吗?
发表于 2021-04-11 13:19:30 回复(0)
<p>构造函数及析构函数内部是不能进行多态的,因为虚函数就需要一个指向虚函数表的指针</p><p><br></p><p><br></p>
发表于 2020-06-14 17:01:16 回复(0)
在父类的构造函数中调用虚函数,表现的函数为父类的虚函数
发表于 2020-02-16 16:45:19 回复(0)
虚函数只判断第一次调用。
发表于 2018-06-11 09:04:16 回复(0)
这道题主要是要了解虚函数表中虚函数的排列顺序,CSDN上有一个非常好的博客。
发表于 2018-03-22 18:41:57 回复(0)
在构造的时候虚函数表还没有创建,虚函数不起作用;在析构函数中也不要调用虚函数,因为虚函数表已经销毁
编辑于 2018-04-07 18:17:42 回复(0)