Вызов виртуальной функции с использованием объекта, созданного в стеке - PullRequest
0 голосов
/ 01 декабря 2019

У меня есть простой класс CTest с двумя функциями - func() и virtualFunc(). Я создаю объект в стеке исключительно для целей тестирования и хочу наблюдать за его поведением. Я понимаю, что мы должны создать объект, используя ключевое слово new в куче, но мне интересно знать поведение виртуальной функции, когда объект находится в стеке.

С кодом, который яв настоящее время это приводит к ошибке сегмента, когда я пытаюсь вызвать виртуальную функцию. Может кто-нибудь сказать мне, почему виртуальная функция приводит к ошибке сегмента, а не виртуальная - нет?

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.

}

Ответы [ 2 ]

6 голосов
/ 01 декабря 2019
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(); работает, а не segfault, на самом деле является неудачей. Методы не хранятся внутри объекта. Они хранятся в секции кода исполняемого файла, один раз для всей программы, а не экземпляра, как обычные функции. Они также переводятся в нечто вроде:

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

И поскольку this недопустимо, но не используется, ничего явно не происходит.

В случае виртуальных функций каждая виртуальная функциявызов функции фактически читает this, чтобы получить то, что называется vtable. Здесь происходит сбой вашей программы, так как this является нулевым указателем.

0 голосов
/ 01 декабря 2019

Вам нужно создать объект, вызвав obj = new CTest вместо obj = NULL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...