使用在堆栈上创建的对象调用虚拟函数

问题描述 投票:0回答:2

我有一个简单的CTest类,具有两个函数-func()virtualFunc()。我仅出于测试目的而在堆栈上创建一个对象,并希望观察其行为。我确实意识到我们应该在堆上使用new关键字创建一个对象,但是我有兴趣知道对象在堆栈上时虚函数的行为。

使用我当前拥有的代码,当我尝试调用虚拟函数时,这会导致Seg Fault。谁能告诉我为什么虚拟功能导致段错误而非虚拟功能却没有?

class CTest {
    public:
        void func() {
            printf("function was called.\n");
        }   
        virtual void virtualFunc() {
            printf("virtual function was called.\n");
        }   
};

int main (int argc, char ** argv) {
    CTest * obj = NULL;

    obj->func(); // this would print "function called" as what's inside the func()

    obj->virtualFunc(); 
    //line above results in segfault because C *obj is on stack; 
    //You would need to allocated obj on the heap for the virtual function to not Seg Fault.WHY?
    //by using "C*obj = new C", I am able to print the contents of virtualFunc() successfully.

}
c++ segmentation-fault virtual-functions
2个回答
4
投票
CTest * obj = NULL;

这不是您在堆栈上创建对象的方式。这是在堆栈上创建对象指针并将其指向任何地方的方法。

您可以简单地做:

CTest obj; // This creates the object, calls constructor

由于对象被视为引用,而不是指针,因此可以使用

obj.func();
obj.virtualFunc();

要使用指向堆栈变量的指针,您可以做:

CTest obj_value; // This actually creates the object
CTest * obj = &obj_value; // This creates pointer to stack object

对象是在堆栈上还是在堆上都不会影响虚拟函数的行为。

在您的情况下,obj->func();有效且不存在段错误的事实实际上是一种不幸。方法未存储在对象内部。它们存储在可执行文件的代码部分中,就像常规函数一样,每个实例(而不是实例)存储一次。它们也被翻译为:

CTest::func(CTest * this) // here this is obj

并且由于this无效但未被使用,所以显然没有发生任何错误。

[对于虚拟函数,每个虚拟函数调用实际上都读取this以得到所谓的vtable。这是您的程序崩溃的地方,因为this是空指针。


-1
投票

您需要通过调用obj = new CTest来创建对象,而不是obj = NULL

© www.soinside.com 2019 - 2024. All rights reserved.