Почему переопределение и глобального нового оператора, и оператора, специфичного для класса, не является неоднозначным?
В следующем разделе рассматривается разрешение перегрузки, поскольку это помогает в основах перегрузки и переопределения.
Предсказать результат:
#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 ++ предоставляет такую расширяемость для новой функции?
- Производительность: встроенная функция распределения памяти является функцией общего назначения и подходит для предопределенных типов данных. Для определяемых пользователем типов данных, которые имеют очень специфические данные, которые должны быть выделены, и, настраивая способ их распределения, вы можете значительно ускорить управление памятью.
- Отладка и статистика: контроль над расходом памяти обеспечивает большую гибкость для отладки, статистики и анализа производительности.
Это некоторые из различных причин, чтобы упростить программирование при решении сложных задач.