Оператор вызова функции: ()
Вызов функции — это тип postfix-expression , сформированный выражением, которое вычисляет функцию или вызываемый объект, за которым следует оператор вызова функции. () Объект может объявить функцию operator () , которая предоставляет семантику вызова функции для объекта.
Синтаксис
postfix-expression :
postfix-expression ( argument-expression-list opt )
Замечания
Аргументы оператора вызова функции приходят из argument-expression-list списка выражений, разделенных запятыми. Значения этих выражений передаются функции в качестве аргументов. Список аргументов-выражений может быть пустым. До C++17 порядок вычисления выражения функции и выражений аргументов не определен и может произойти в любом порядке. В C++17 и более поздних версиях выражение функции вычисляется до любых выражений аргументов или аргументов по умолчанию. Выражения аргументов вычисляются в неопределенной последовательности.
Функция postfix-expression вычисляет вызываемую функцию. Он может принимать любую из нескольких форм:
- идентификатор функции, видимый в текущей область или в область любого из указанных аргументов функции,
- выражение, которое вычисляет функцию, указатель функции, вызываемый объект или ссылку на одну,
- метод доступа к функции-члену( явный или подразумеваемый)
- разыменовыватель указателя на функцию-член.
Может postfix-expression быть перегруженный идентификатор функции или перегруженный метод доступа к функции-члену. Правила разрешения перегрузки определяют фактическую функцию для вызова. Если функция-член является виртуальной, функция для вызова определяется во время выполнения.
Некоторые примеры объявлений:
-
Функция, возвращающая тип T . Пример объявления:
T func( int i );
T (*func)( int i );
(pObject->*pmf)(); (Object.*pmf)();
Пример
В следующем примере вызывается функция стандартной библиотеки strcat_s с тремя аргументами:
// expre_Function_Call_Operator.cpp // compile with: /EHsc #include #include // C++ Standard Library name space using namespace std; int main() < enum < sizeOfBuffer = 20 >; char s1[ sizeOfBuffer ] = "Welcome to "; char s2[ ] = "C++"; strcat_s( s1, sizeOfBuffer, s2 ); cout
Welcome to C++
Результаты вызова функции
Вызов функции вычисляется на значение rvalue, если функция не объявлена как ссылочный тип. Функции с ссылочными возвращаемыми типами оцениваются на lvalues. Эти функции можно использовать в левой части инструкции назначения, как показано ниже:
// expre_Function_Call_Results.cpp // compile with: /EHsc #include class Point < public: // Define "accessor" functions as // reference types. unsigned& x() < return _x; >unsigned& y() < return _y; >private: unsigned _x; unsigned _y; >; using namespace std; int main() < Point ThePoint; ThePoint.x() = 7; // Use x() as an l-value. unsigned y = ThePoint.y(); // Use y() as an r-value. // Use x() and y() as r-values. cout
Приведенный выше код определяет класс, который Point содержит объекты частных данных, представляющие координаты x и y . Эти объекты данных необходимо изменить, а значения — извлечь. Программа — это лишь одно из нескольких решений для такого класса. Также можно использовать функции GetX и SetX или GetY и SetY .
Функции, возвращающие типы классов, указатели на типы классов или ссылки на типы классов можно использовать как левый операнд в операторах выбора члена. Следующий код является законным:
// expre_Function_Results2.cpp class A < public: A() <>A(int i) <> int SetA( int i ) < return (I = i); >int GetA() < return I; >private: int I; >; A func1() < A a = 0; return a; >A* func2() < A *a = new A(); return a; >A& func3() < A *a = new A(); A &b = *a; return b; >int main() < int iResult = func1().GetA(); func2()->SetA( 3 ); func3().SetA( 7 ); >
Функции можно вызывать рекурсивно. Дополнительные сведения о объявлениях функций см. в разделе "Функции". Связанные материалы относятся к единицам перевода и компоновке.
Как вызвать функцию класса из переменной?
Подскажите пожалуйста, каким образом, можно в C++ сохранить функцию класса в переменную, и затем вызвать её из основного тела программы? Если делать всё просто в main, без разделение на классы, то всё работает. Я же хочу сделать именно в разных файлах.
Как бы я не пытался придумать, у меня выходит ошибка:
non-standard syntax; use '&' to create a pointer to member
Пробую как-то так:
//Class.h: class Class < public: typedef void(Class::*funcType)(); funcType func; void test(); >; //Class.cpp: #include "Class.h" #include Class::Class() < func = Class::test; >void Class::test() < std::cout //Program.cpp #include #include "Class.h" void mian()
Отслеживать
задан 5 июн 2019 в 11:21
3 1 1 бронзовый знак
К тому же указатель на метод немного отличается от указателя на функцию. Ему нужен объект, к которому этот указатель на метод мы можем применить. И тогда получится такая штука (c.*c.func)();
5 июн 2019 в 11:49
Пробовал ставить * и & в различных комбинациях, это не изменяло ошибку. Что-то не пойму, как использовать (c.*c.func)
Вызвать метод класса в потоке, С++
Добрый день! Изучаю ООП С++, попутно переписываю старые программы в стиле ООП, наткнулся на проблему. Есть объект Х класса Test, в классе есть два метода, допустим метод А и метод Б, метод А крутится в цикле и ожидает определенного события, когда событие происходит метод А должен вызвать метод Б в параллельном потоке (thread t1) и открепить (t1.detach()) его, в свою очередь метод Б должен иметь возможность продолжать работать с объектом Х. Подскажите как это правильно реализовать? Для запуска обычной функции в потоке, все было просто
thread t1(Function, Param1, Param2); t1.detach();
С методами, понятное дел, так не получается, буду благодарен за пример или объяснение.
VladV
29.05.17 12:05:53 MSK
Функции (C++)
Функции — это блоки кода, выполняющие определенные операции. Если требуется, функция может определять входные параметры, позволяющие вызывающим объектам передавать ей аргументы. При необходимости функция также может возвращать значение как выходное. Функции полезны для инкапсуляции основных операций в едином блоке, который может многократно использоваться. В идеальном случае имя этого блока должно четко описывать назначение функции. Следующая функция принимает два целых числа из вызывающего средства и возвращает их сумму; a и b — это параметры типа int .
int sum(int a, int b)
Функция может вызываться или вызываться из любого количества мест в программе. Значения, передаваемые функции, являются аргументами, типы которых должны быть совместимы с типами параметров в определении функции.
int main() < int i = sum(10, 32); int j = sum(i, 66); cout
Нет практического ограничения на длину функции, но хороший дизайн предназначен для функций, выполняющих одну хорошо определенную задачу. Сложные алгоритмы лучше разбивать на более короткие и простые для понимания функции, если это возможно.
Функции, определенные в области видимости класса, называются функциями-членами. В C++, в отличие от других языков, функции можно также определять в области видимости пространства имен (включая неявное глобальное пространство имен). Такие функции называются бесплатными или не-членными функциями; они широко используются в стандартной библиотеке.
Функции могут быть перегружены, что означает, что разные версии функции могут совместно использовать одно и то же имя, если они отличаются числом и /или типом формальных параметров. Дополнительные сведения см. в разделе "Перегрузка функций".
Части объявления функции
Минимальное объявление функции состоит из возвращаемого типа, имени функции и списка параметров (которые могут быть пустыми), а также необязательных ключевое слово, которые предоставляют дополнительные инструкции компилятору. В следующем примере представлено объявление функции:
int sum(int a, int b);
Определение функции состоит из объявления, а также текста, который представляет собой весь код между фигурными скобками:
int sum(int a, int b)
Объявление функции, за которым следует точка с запятой, может многократно встречаться в разных местах кода программы. Оно необходимо перед любыми вызовами этой функции в каждой записи преобразования. По правилу одного определения, определение функции должно фигурировать в коде программы лишь один раз.
При объявлении функции необходимо указать:
- Возвращаемый тип, указывающий тип значения, возвращаемого функцией, или void если значение не возвращается. В C++11 является допустимым типом возвращаемого значения, auto который указывает компилятору выводить тип из инструкции return. В C++14 decltype(auto) также разрешено. Дополнительные сведения см. в подразделе "Выведение возвращаемых типов" ниже.
- Имя функции, которое должно начинаться с буквы или подчеркивания и не может содержать пробелы. Как правило, ведущие подчеркивания в именах функций стандартной библиотеки указывают на частные функции-члены или функции, не являющиеся членами, которые не предназначены для использования в коде.
- Список параметров, заключенный в скобки. В этом списке через запятую указывается нужное (возможно, нулевое) число параметров, задающих тип и, при необходимости, локальное имя, по которому к значениям можно получить доступ в теле функции.
Необязательные элементы объявления функции:
-
constexpr — указывает, что возвращаемое значение функции является константой, значение которой может быть определено во время компиляции.
constexpr float exp(float x, int n) < return n == 0 ? 1 : n % 2 == 0 ? exp(x * x, n / 2) : exp(x * x, (n - 1) / 2) * x; >;
//Declare printf with C linkage. extern "C" int printf( const char *fmt, . );
inline double Account::GetBalance()
#include template T copy_object(T& obj) noexcept(std::is_pod)
Определения функций
Определение функции состоит из объявления и текста функции, заключенного в фигурные скобки, которые содержат объявления переменных, операторы и выражения. В следующем примере показано полное определение функции:
int foo(int i, std::string s) < int value ; MyClass mc; if(strcmp(s, "default") != 0) < value = mc.do_something(i); >return value; >
Переменные, объявленные в теле функции, называются локальными. Они исчезают из области видимости при выходе из функции, поэтому функция никогда не должна возвращать ссылку на локальную переменную.
MyClass& boom(int i, std::string s) < int value ; MyClass mc; mc.Initialize(i,s); return mc; >
функции const и constexpr
Можно объявить функцию-член, чтобы const указать, что функция не может изменять значения элементов данных в классе. Объявив функцию-член как const , компилятор помогает обеспечить правильность константа. Если кто-то ошибочно пытается изменить объект с помощью функции, объявленной как const , возникает ошибка компилятора. Дополнительные сведения см. в разделе const.
Объявите функцию, как constexpr когда значение, которое он создает, может быть определено во время компиляции. Функция constexpr обычно выполняется быстрее, чем обычная функция. Дополнительные сведения см. в разделе constexpr .
Шаблоны функций
Шаблоны функций подобны шаблонам классов. Их задача заключается в создании конкретных функций на основе аргументов шаблонов. Во многих случаях шаблоны могут определять типы аргументов, поэтому их не требуется явно указывать.
template auto Add2(const Lhs& lhs, const Rhs& rhs) < return lhs + rhs; >auto a = Add2(3.13, 2.895); // a is a double auto b = Add2(string< "Hello" >, string< " World" >); // b is a std::string
Дополнительные сведения см. в разделе "Шаблоны функций"
Параметры и аргументы функций
У функции имеется список параметров, в котором через запятую перечислено необходимое (возможно, нулевое) число типов. Каждому параметру присваивается имя, по которому к нему можно получить доступ в теле функции. Шаблон функции может указывать дополнительные параметры типа или значения. Вызывающий объект передает аргументы, представляющие собой конкретные значения, типы которых совместимы со списком параметров.
По умолчанию аргументы передаются функции по значению, то есть функция получает копию передаваемого объекта. Для больших объектов копирование может быть дорогостоящим и не всегда требуется. Чтобы привести к передаче аргументов по ссылке (в частности, ссылке lvalue), добавьте к параметру квантификатор ссылок:
void DoSomething(std::string& input)
Если функция изменяет аргумент, передаваемый по ссылке, изменяется исходный объект, а не его локальная копия. Чтобы предотвратить изменение такого аргумента функции, квалифицируйте параметр как const&:
void DoSomething(const std::string& input)
C++11. Чтобы явно обрабатывать аргументы, передаваемые rvalue-reference или lvalue-reference, используйте двойной амперсанд для параметра, чтобы указать универсальную ссылку:
void DoSomething(const std::string&& input)
Функция, объявленная с одним ключевое слово void в списке объявлений параметров, не принимает аргументов, если ключевое слово void является первым и единственным членом списка объявлений аргументов. Аргументы типа void в другом месте списка создают ошибки. Например:
// OK same as GetTickCount() long GetTickCount( void );
Хотя это недопустимо указывать void аргумент, кроме описанного здесь, типы, производные от типа void (например, указателей на void и массивы) могут отображаться в любом месте списка объявлений void аргументов.
Аргументы по умолчанию
Последним параметрам в сигнатуре функции можно назначить аргумент по умолчанию, т. е. вызывающий объект сможет опустить аргумент при вызове функции, если не требуется указать какое-либо другое значение.
int DoSomething(int num, string str, Allocator& alloc = defaultAllocator) < . >// OK both parameters are at end int DoSomethingElse(int num, string str = string< "Working" >, Allocator& alloc = defaultAllocator) < . >// C2548: 'DoMore': missing default parameter for parameter 2 int DoMore(int num = 5, // Not a trailing parameter! string str, Allocator& = defaultAllocator)
Дополнительные сведения см. в разделе "Аргументы по умолчанию".
типов возвращаемых функциями значений;
Функция может не возвращать другую функцию или встроенный массив; однако он может возвращать указатели на эти типы или лямбда-объект, который создает объект функции. За исключением этих случаев, функция может возвращать значение любого типа, который находится в область, или не возвращать никакого значения, в этом случае возвращаемый тип. void
Завершающие возвращаемые типы
"Обычные" возвращаемые типы расположены слева от сигнатуры функции. Конечный возвращаемый тип находится в правой части подписи и предшествует оператору -> . Завершающие возвращаемые типы особенно полезны в шаблонах функций, когда тип возвращаемого значения зависит от параметров шаблона.
template auto Add(const Lhs& lhs, const Rhs& rhs) -> decltype(lhs + rhs)
Если auto используется в сочетании с конечным типом возвращаемого значения, он просто служит заполнителем для любого создаваемого выражения деклтипа и не выполняет вычет типов.
Локальные переменные функции
Переменная, объявленная внутри тела функции, называется локальной переменной или просто локальной . Нестатические локальные локальные параметры отображаются только внутри тела функции, и если они объявлены в стеке выходят из область при выходе функции. При создании локальной переменной и возврате ее по значению компилятор обычно может выполнять оптимизацию именованных возвращаемых значений, чтобы избежать ненужных операций копирования. Если локальная переменная возвращается по ссылке, компилятор выдаст предупреждение, поскольку любые попытки вызывающего объекта использовать эту ссылку произойдут после уничтожения локальной переменной.
В C++ локальные переменные можно объявлять как статические. Переменная является видимой только в теле функции, однако для всех экземпляров функции существует только одна копия переменной. Локальные статические объекты удаляются во время завершения, определенного директивой atexit . Если статический объект не был создан, так как поток управления программы обошел его объявление, попытка уничтожить этот объект не выполняется.
Вычет типов в возвращаемых типах (C++14)
В C++14 можно использовать auto для указания компилятору выводить тип возвращаемого значения из тела функции, не предоставляя конечный тип возвращаемого значения. Обратите внимание, что auto всегда дедуцирует возвращаемое значение. Используйте auto&& , чтобы дать компилятору команду выведения ссылки.
В этом примере auto будет выведено в виде копии неконстантных значений суммы lhs и rhs.
template auto Add2(const Lhs& lhs, const Rhs& rhs) < return lhs + rhs; //returns a non-const object by value >
Обратите внимание, что auto не сохраняет константность типа, который он выводит. Для переадресации функций, возвращаемые значением которых необходимо сохранить констант-ness или ref-ness его аргументов, можно использовать decltype(auto) ключевое слово, которая использует decltype правила вывода типов и сохраняет все сведения о типе. decltype(auto) может использоваться в качестве обычного возвращаемого значения слева или в качестве возвращаемого значения.
В следующем примере (на основе кода из N3493) показано decltype(auto) , что используется для обеспечения идеальной пересылки аргументов функций в возвращаемом типе, который не известен до создания шаблона.
template, int. I> decltype(auto) apply_(F&& f, Tuple&& args, index_sequence) < return std::forward(f)(std::get(std::forward(args)). ); > template, typename Indices = make_index_sequence> decltype( auto) apply(F&& f, Tuple&& args) < return apply_(std::forward(f), std::forward(args), Indices()); >
Возврат нескольких значений из функции
Существует несколько способов возврата нескольких значений из функции:
-
Инкапсулируйте значения в именованном классе или объекте структуры. Требуется, чтобы определение класса или структуры отображалось вызывающей объекту:
#include #include using namespace std; struct S < string name; int num; >; S g() < string t< "hello" >; int u< 42 >; return < t, u >; > int main()
#include #include #include using namespace std; tuple f() < int i< 108 >; string s< "Some text" >; double d< .01 >; return < i,s,d >; > int main() < auto t = f(); cout (t) (t) (t)#include #include #include using namespace std; tuple f() < int i< 108 >; string s< "Some text" >; double d< .01 >; return < i,s,d >; > struct S < string name; int num; >; S g() < string t< "hello" >; int u< 42 >; return < t, u >; > int main() < auto[x, y, z] = f(); // init from tuple coutУказатели функций
Как и в C, в C++ поддерживаются указатели на функции. Однако более типобезопасной альтернативой обычно служит использование объекта-функции.
Рекомендуется typedef объявить псевдоним для типа указателя функции при объявлении функции, возвращающей тип указателя функции. Например.
typedef int (*fp)(int); fp myFunction(char* s); // function returning function pointerЕсли это не сделано, правильный синтаксис объявления функции может быть выведен из синтаксиса декларатора для указателя функции, заменив идентификатор ( fp в приведенном выше примере) именем функций и списком аргументов следующим образом:
int (*myFunction(char* s))(int);Предыдущее объявление эквивалентно объявлению, используемому typedef ранее.