Почему переопределение и глобального нового оператора, и оператора, специфичного для класса, не является неоднозначным?

Опубликовано: 6 Июля, 2021

В следующем разделе рассматривается разрешение перегрузки, поскольку это помогает в основах перегрузки и переопределения.
Предсказать результат:




#include <iostream>
using namespace std;
class Gfg {
public :
void printHello()
{
cout << "hello gfg-class specific" << endl;
}
};
void printHello()
{
cout << "hello gfg-global" << endl;
}
int main()
{
Gfg a;
a.printHello();
printHello();
}
 Выход:
привет, специфичный для класса gfg
привет gfg-global

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

Предсказать результат:




#include <iostream>
using namespace std;
class Gfg {
public :
Gfg operator+(Gfg& a)
{
cout << "class specific + operator" << endl;
return Gfg(); // Just return some temporary object
}
};
Gfg operator+(Gfg& a, Gfg& b)
{
cout << "global + operator called" << endl;
return Gfg(); // Just return some temporary object
}
int main()
{
Gfg a, b;
Gfg c = a + b;
}
 Вывод: ошибка компиляции
plusOverride.cpp: В функции int main ():
plusOverride.cpp: 19: 9: ошибка: неоднозначная перегрузка для 'operator +' 
(типы операндов - Gfg и Gfg)
  Gfg c = a + b;
         ^
plusOverride.cpp: 19: 9: note: кандидатами являются:
plusOverride.cpp: 6: 9: примечание: Gfg Gfg :: operator + (Gfg &)
     Оператор Gfg + (Gfg & a) {
         ^
plusOverride.cpp: 12: 5: примечание: оператор Gfg + (Gfg &, Gfg &)
 Оператор Gfg + (Gfg & a, Gfg & b) {
     ^

Вот как разрешение перегрузки работает с перегрузкой оператора:
Функции-кандидаты для унарных и бинарных операторов выбираются из разных областей. Они есть
1) кандидаты в члены: функции, перегруженные оператором, определенные в классе.
2) кандидаты, не являющиеся членами: оператор перегружает функции, которые являются глобальными.
3) встроенные кандидаты: встроенные функции, выполняющие указанную операцию.
Следовательно, для вышеуказанной программы во время компиляции количество функций-кандидатов больше одной, и все эти функции-кандидаты имеют одинаковый приоритет, и, следовательно, возникает неоднозначная ошибка перегрузки.
Предсказать результат:




#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class Gfg {
public :
int a;
void * operator new ( size_t sz)
{
cout << "class-specific new for size " << sz << ' ' ;
return malloc (sz);
}
void * operator new []( size_t sz)
{
cout << "class-specific new[] for size " << sz << ' ' ;
return malloc (sz);
}
};
void * operator new []( size_t sz)
{
cout << "global new[] for size" << sz << ' ' ;
return malloc (sz);
}
void * operator new ( size_t sz)
{
cout << "global new for size" << sz << ' ' ;
return malloc (sz);
}
int main()
{
Gfg* p1 = new Gfg;
delete p1;
Gfg* p2 = new Gfg[10];
delete [] p2;
}
 Выход: 
новинка класса 4 размера
новый для класса [] для размера 40

Программа работала по следующим причинам:
Стандарты C ++ гласят: «Если класс имеет специфичную для класса функцию распределения, то будет вызываться именно функция, а не глобальная функция распределения. Это сделано намеренно: ожидается, что член класса лучше всех знает, как обращаться с этим классом ». Это означает, что когда новое выражение ищет соответствующую функцию распределения, оно начинается в области видимости класса перед исследованием глобальной области, и если предоставляется специфичное для класса new, оно вызывается. В противном случае он проверяет глобальную область видимости и вызывает ее. Если новая функция глобальной области видимости отсутствует, она вызовет встроенную новую функцию. Отныне функции-кандидаты не имеют такого же приоритета в приведенном выше примере, и, следовательно, он компилируется без каких-либо ошибок.

Может ли программист вызвать глобальный оператор new, даже если определен оператор new для конкретного класса?
Да. C ++ предоставляет для этой цели оператор разрешения области видимости. Если перед оператором new стоит оператор разрешения области видимости (: :), компилятор ищет оператор new в глобальной области видимости.

Что произойдет, если оператор new не определен в глобальной области видимости и вы вызываете оператор new с помощью оператора :: unary?
Компилятор вызовет встроенную новую функцию. В следующем примере показано, как это работает. Он содержит специфичный для класса оператор new, но глобальный оператор new. Отныне при вызове :: new компилятор вызывает новую функцию стандартной библиотеки.




#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class Gfg {
public :
int a;
void * operator new ( size_t sz)
{
cout << "class-specific new for size " << sz << ' ' ;
return malloc (sz);
}
void * operator new []( size_t sz)
{
cout << "class-specific new[] for size " << sz << ' ' ;
return malloc (sz);
}
};
void * operator new []( size_t sz)
{
cout << "global new[] for size " << sz << ' ' ;
return malloc (sz);
}
int main()
{
Gfg* p1 = :: new Gfg;
cout << "Allocated sie of p1: " << sizeof (*p1) << endl;
delete p1;
Gfg* p2 = :: new Gfg[10];
delete [] p2;
}
 Выход:
Выделено sie p1: 4
global new [] для размера 40

Почему C ++ предоставляет такую расширяемость для новой функции?

  1. Производительность: встроенная функция распределения памяти является функцией общего назначения и подходит для предопределенных типов данных. Для определяемых пользователем типов данных, которые имеют очень специфические данные, которые должны быть выделены, и, настраивая способ их распределения, вы можете значительно ускорить управление памятью.
  2. Отладка и статистика: контроль над расходом памяти обеспечивает большую гибкость для отладки, статистики и анализа производительности.

Это некоторые из различных причин, чтобы упростить программирование при решении сложных задач.

Хотите узнать больше о лучших видео и практических задачах, ознакомьтесь с базовым курсом C ++ для базового и продвинутого уровней C ++ и курсом C ++ STL для базового уровня плюс STL. Чтобы завершить подготовку от изучения языка к DS Algo и многому другому, см. Полный курс подготовки к собеседованию .