愿你坚持不懈,努力进步,进阶成自己理想的人

—— 2017.09, 写给3年后的自己

关于C++多态应用时出现“Pure virtual function called!”的分析

今天有同学拿一道C++多态的题目问我出错在哪,下面我结合这道问题,精简下代码,分析问题所在。

来看示例的代码:

#include <iostream>

using namespace std;


class Base {

protected:

    string name;

public:

    Base(string nam):name(nam){}

    virtual void display() = 0;

};


class Hello: public Base {

public:

    Hello(string name):Base(name){}

    ~Hello(){}

    void display() {

        cout << "Hello, " << name;

    }

};


int main() {

    int i=0;

    string name;

    Base *pointer[10];

    

    while(cin>>name) {

        if(name=="0") break;

        Hello demo(name);

        pointer[i] = &demo;

        i++;

    }

    for(int j=0; j<i; j++) {

        pointer[j]->display();

    }

    

    return 0;

}

在这里,运行后,编译器会提示(我用的是XCode):

libc++abi.dylib: Pure virtual function called!


对于这个问题,我尝试地把

        Hello demo(name);

        pointer[i] = &demo;

这里进行了修改,改成了以下代码:

        pointer[i] = new Hello(name);

再对程序进行编译,发现编译就可以通过了


这是为什么呢?

        首先,我们知道C++和C语言的一个不同的地方就是在C++中变量不必在最前面进行声明。

        我们可以在任何地方,在需要的时候进行声明,但是变量是有作用域的,像在花括号内就是一个作用域。

        像修改前的代码,Hello demo(name);是在局部进行声明的,它的作用域为当前花括号内,当退出这个作用域的时候,之前demo所在的内存空间就被释放掉了,这时候,&demo的这段内存空间也就不复存在,pointer[i]又是指向&demo这段内存空间的。在最后pointer[j]->display()的时候,由于它之前指向的内存空间已经被释放,所以,这时候根据多态的原理,pointer[j]是不知道指向哪个派生类对象的,这时候它只能调用本身,然而因为Base类已经被声明为纯虚函数,纯虚函数是不可以实例化的,自然会导致编译器提示:Pure virtual function called.

        然后,通过new运算符进行动态分配的对象,由于还没有进行delete操作,所以它那段空间是存在的,再综合以上分析,自然用new运算符进行动态内存分配就行得通了~~