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

use*_*123 -1 c++ virtual-functions segmentation-fault

我有一个带有两个函数的简单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.

}
Run Code Online (Sandbox Code Playgroud)

pek*_*u33 5

CTest * obj = NULL;
Run Code Online (Sandbox Code Playgroud)

This is NOT how you create object on stack. This is how you create object pointer on stack and point it to nowhere.

You can simply do:

CTest obj; // This creates the object, calls constructor
Run Code Online (Sandbox Code Playgroud)

And since the object is treated like reference, not pointer, you can use

obj.func();
obj.virtualFunc();
Run Code Online (Sandbox Code Playgroud)

etc.

To use pointer to stack variable, you can do:

CTest obj_value; // This actually creates the object
CTest * obj = &obj_value; // This creates pointer to stack object
Run Code Online (Sandbox Code Playgroud)

Whether the object is on stack or heap does not affect behavior of virtual functions.

In your case, the fact that obj->func(); works and does not segfault is actually a bad luck. Methods are not stored inside the object. They are stored in code section of executable, once per whole program, not instance, just like regular functions. They are also translated to something like:

CTest::func(CTest * this) // here this is obj
Run Code Online (Sandbox Code Playgroud)

And since this is invalid, but it is not used, nothing visibly wrong happens.

In case of virtual functions, each virtual function call actualy reads this to get what is called vtable. This is where your program crashes, as this is null pointer.