вызов функции через указатель без выделения памяти из объекта

#c #class #pointers #member-functions

#c #класс #указатели #функции-члены

Вопрос:

У меня есть класс как

 class BTree {
    public:
    int val;
    BTree *next;
    BTree *child;
    BTree* putVal(int v) {
        BTree *temp = new BTree;
        temp->val = v;
        return temp;
    }
}*root;
  

может ли это использоваться как?

 root = root->putVal(12);
printf("%x %dn",root,root->val);  
  

Выше напечатано root = 0 перед вызовом putVal и некоторое место в памяти после вызова.
Вероятно, это очень плохой код, но я просто хочу знать, разрешено ли это и будет ли работать должным образом?

Как вызываются функции?

Из синтаксиса вызова оказалось, что каждая переменная имеет копию указателя на функции в классе. В этом случае это не должно работать, поскольку память еще не выделена для объекта.

Ответ №1:

Нет, это не разрешено. Использование нулевых указателей не допускается, и «вызов функции-члена» считается использованием.

Есть несколько вещей, которые вы можете сделать с нулевыми указателями, которые не считаются используемыми. Сравнение их с другими указателями и присвоение новых значений являются двумя наиболее распространенными.

Основная причина заключается в том, что нулевой указатель не указывает на объект, а для вызова функции-члена объекта требуется фактический объект.

Ответ №2:

У вас есть неопределенное поведение — вызывающие методы с использованием нулевого указателя объекта — это UB. Однако, чтобы ответить на ваш вопрос, почему это вообще работает в вашем случае — в большинстве компиляторов в объекте хранятся только адреса виртуальных функций. Невиртуальные функции, такие как ваша putVal , вызываются аналогично глобальным функциям, только у них есть дополнительный скрытый параметр, указывающий на объект.

На практике это означает, что во многих случаях, если вы вызываете виртуальную функцию, используя нулевой указатель, она сразу же вылетит. Если вы вызываете невиртуальную функцию, то она завершится сбоем при первом обращении к объекту в теле функции (доступ означает — поле считывается или записывается, или вызывается виртуальная функция). Поскольку ваша функция вообще не обращается к вашему объекту, сбоя нет.

Опять же, у вас есть UB, и такой код никогда не следует использовать. Даже с учетом описанных выше деталей реализации (которые могут быть правдой, а могут и не быть) вы не хотите делать функцию виртуальной или обновлять компилятор и получать неожиданные сбои. Но я думаю, что это стоит того, чтобы понять, как выглядит обычная реализация вызова метода в C .

Ответ №3:

Как упоминали другие одноранговые узлы, нулевой указатель не является объектом, и попытка доступа к функциям-членам приводит к сбою, но функция PutVal имеет атрибуты, позволяющие стать статической функцией.

PutVal принимает значение int и создает объект из аргумента. putVal не выполняет операций над объектом, а инициализирует его.

Сделайте putVal статическим для лучшей реализации.