记录一道C++面试题 -- 构造函数中调用虚函数

题目:以下程序运行的结果是什么?

class A {
public:
    A() {
        std::cout << "create A" << std::endl;
        virFunc();
    }

    virtual void virFunc() {
        std::cout << "A virFunc" << std::endl;
    }   
};

class B : public A {
public:
    B() {
        std::cout << "create B" << std::endl;
        virFunc();
    }

    virtual void virFunc() {
        std::cout << "B virFunc" << std::endl;
    }   
};

int main() {
    A *p = new B();
    delete p;   
    return 0;
}

这可能有个陷阱,创建子类对象,构造函数先调用父类的,再调用子类的构造函数,这里又由于 virFunc 是虚函数,所以根据虚函数的机制,应该会有以下输出:

create A
B virFunc
creat B
B virFunc

貌似看起来没啥问题,可是实际上上述输出的第二行是错误的,不信你可以在自己的电脑上试试,正确的答案应该为:

create A
A virFunc
create B
B virFunc

很多同学不理解,virFunc 不是虚函数吗?怎么会调用父类本身的那个实现体,不是应该调用子类的那个吗?

请你再回想下虚函数机制的作用时机…

虚函数产生多态的时机是:

  • 1) 通过父类的指针去调用虚函数,此时父类的指针实际上指向某个子类型。
  • 2) 通过父类的引用去调用虚函数,此时父类的引用实际上引用的是某个子类型。

这样就可以理解为什么上述第二行的输出结果会是 A virFunc 了,当 new B() 执行时,首先调用父类的构造函数,即调用 A 的构造函数,我们都知道,在类的成员函数中有一个隐藏的 this 指针,代表的是当前对象的地址,在调用 A() 时,传递给 A()this 指针应该是新创建的 B 的对象的地址,所以 A() 可类似为:

A(this) { // 此时的 this 为新创建的 B 的对象的指针
    std::cout << "create A" << endl;
    this->A::virFunc(); // 这里实际上是通过子类的指针去调用父类中的函数,没有产生多态的效应
}

所以对于 C++ 的很多语法,只有真正理解了,或者说了解其底层相关的机制,才能在遇到相关问题的时候能够胸有成竹,而不会出现模棱两可的现象。

另外插一个额外的语法点,也是面试中的题目:static member functions 不能被 const 修饰,会出现编译错误。但是 const 可以修饰 static data members

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值