HTML [44] |
Visual C++ и MFC [21] |
c++ [78] |
php [19] |
Javascript [15] |
C# [51] |
загрузки [0] |
XNA
[10]
создание игр с помощью xna
|
Главная » Статьи » c++ |
Произвольное количество и тип аргументов?! Хмм... Возможно ли это? Возможно, если в прототипе некоторой функции последним аргументом (ПОСЛЕДНИМ!!!) указать многоточие (...). Рассмотрим, например, известную вам по прошлым урокам библиотечную функцию printf. Ее прототип выглядит следующим образом: int printf(const char *format, ...); Такое написание означает, что функция имеет один обязательный параметр (строка) и неопределенное количество (>=0) необязательных. Казалось бы здорово! Кроме того что количество параметров у функции неограничено, эти параметры могут быть любого типа. Однако за все приходиться платить - функции необходимо узнать сколько же параметров ей передано и какого типа каждый из них. Решить эту проблему можно несколькими способами. Например, функция printf подсчитывает количество переданных параметров с помощью подсчета знаков %, которые вы вставляете в первый параметр функции (вариант %% является исключением), а тип каждого параметра распознает по модификатору, идущему за знаком % (например, %d - это целое число). Именно поэтому "обмануть" функцию не получается: при расхождении количества знаков % и числа переданных в функцию переменных функция "вылетает", а при несовпадении типов данных отображает чушь. Есть и другие способы. Можно, например, записывать количество передаваемых параметров в первый параметр функции (первый параметр в подавляющем большинстве случаев является обязательным для функций такого рода). Также можно условиться о том какой параметр завершает список. Например, будем считать что для функции void F(int, ...); -1000000 недопустимое число. Тогда при следующем вызове функции: F(1, 2, 3, 4, 5, -1000000); станет возможным определить число переданных аргументов (в данном случае их 5). Как же перебирать аргументы внутри функции? Для этого необходимо подключить библиотеку stdarg.h, объявить переменную типа va_list (на самом деле это эквивалент char*) и воспользоваться следующими функциями:
В качестве примера на изложенный здесь материал (честно говоря, "въехать" в него сразу очень непросто) вам предлагается рассматриваемый ранее проект Vector, который дополнен соответствующей фукцией (см. следующий раздел). Практический пример использования функций с произвольным числом аргументовПримечание: Для облегчения чтения все добавленные в проект Vector части выделены "жирным" шрифтом. Интерфейс класса Vector: // Предотвращение повторной компиляции кода // с помощью директив условной компиляции #ifndef VECTOR_H #define VECTOR_H class Vector { double *vect; // Вектор int size; // Размерность вектора public: Vector(); // Конструктор по умолчанию explicit Vector(int); // Конструктор, позволяющий задавать // размерность вектора, но не являющийся // конструктором преобразования Vector(const double*, int); // Конструктор, позволяющий // проинициализировать вектор с помощью // существующего массива Vector(const Vector&); // Конструктор копирования ~Vector(); // Деструктор double operator ! (); // Функция, вычисляющая длину вектора Vector& operator ++ (); // Увеличение всех компонент вектора // на единицу (префикс) Vector operator ++ (int); // Увеличение всех компонент вектора // на единицу (постфикс) Vector& operator -- (); // Уменьшение всех компонент вектора // на единицу (префикс) Vector operator -- (int); // Уменьшение всех компонент вектора // на единицу (постфикс) Vector& operator = (const Vector&); // Перегруженный оператор присваивания double& operator [] (int); // Перегруженный оператор индексации Vector& operator + (); // Перегруженный оператор + (унарный) Vector operator - (); // Перегруженный оператор - (унарный) Vector operator + (const Vector&); // Сложение двух векторов Vector operator + (double); // Сложение вектора с числом Vector& operator += (const Vector&);// Перегруженный оператор += для // сложения двух векторов Vector& operator += (double); // Перегруженный оператор += для // сложения вектора с числом Vector operator - (const Vector&); // Вычитание двух векторов Vector operator - (double); // Вычитание числа из вектора Vector& operator -= (const Vector&);// Перегруженный оператор -= для // вычитания двух векторов Vector& operator -= (double); // Перегруженный оператор -= для // вычитания числа из вектора double operator * (const Vector&); // Умножение векторов Vector operator * (double); // Умножение вектора на число Vector& operator *= (double); // Перегруженный оператор *= для // умножения вектора на число // Ввод вектора с клавиатуры friend istream& operator >> (istream&, Vector&); // Вывод вектора на экран friend ostream& operator << (ostream&, Vector&); int GetSize(); // Функция возвращает размерность вектора // Вектор с любым количеством элементов, // count - количество аргументов Vector& operator () (unsigned count, ...); }; #endif Реализация класса Vector: #include <iostream.h> #include <math.h> #include "Vector.h" Vector::Vector() { // Конструктор по умолчанию int n; cout << "Input array size:\t"; cin >> n; // Запрос размерности вектора while(n <= 0) // Проверка корректности ввода { cout << "Input array size:\t"; cin >> n; } size = n; vect = new double[size]; // Создание вектора заданной длины } Vector::Vector(int n) { size = n; vect = new double[size]; // Создание вектора заданной длины } Vector::Vector(const double* v, int n) { size = n; vect = new double[size]; for(int i = 0; i < size; i++)// Копирование элементов переданного массива vect[i] = v[i]; // в компоненты вектора } Vector::Vector(const Vector& v) { // Конструктор копирования size = v.size; vect = new double[size]; for(int i = 0; i < size; i++) vect[i] = v.vect[i]; } Vector::~Vector() { // Деструктор delete [] vect; } Vector& Vector::operator = (const Vector& v) { // Перегруженный оператор присваивания if(&v == this) // Проверка на присваивание объекта return *this; // самому себе // Если передан другой объект, то копируем его delete [] vect; size = v.size; vect = new double[size]; for(int i = 0; i < size; i++) vect[i] = v.vect[i]; return *this; } istream& operator >> (istream& is, Vector &v) { // Ввод компонент вектора с клавиатуры for(int i = 0; i < v.size; i++) { cout << "Input vect[" << i << "]:\t"; is >> v.vect[i]; } return is; } ostream& operator << (ostream& os, Vector& v) { // Вывод вектора на экран os << "Vector: ("; for(int i = 0; i < v.size; i++) { os << v.vect[i]; if(i == v.size - 1) os << ")\n"; else os << ", "; } return os; } double Vector::operator ! () { // Перегруженный оператор ! для // вычисления длины вектора double n = 0.0; for(int i = 0; i < size; i++) n += vect[i] * vect[i]; return sqrt(n); } Vector& Vector::operator ++ () { // Увеличение всех компонент вектора // на единицу (префикс) for(int i = 0; i < size; i++) vect[i]++; return *this; } Vector& Vector::operator -- () { // Уменьшение всех компонент вектора // на единицу (префикс) for(int i = 0; i < size; i++) vect[i]--; return *this; } Vector Vector::operator ++ (int n) // n - фиктивный параметр { // Увеличение всех компонент вектора // на единицу (постфикс) Vector temp(*this); // Создание временного объекта и // инициализация его текущим объектом // (объектом, для которого вызвалась функция) for(int i = 0; i < size; i++)// Увеличение компонент вектора на единицу vect[i]++; // (для текущего объекта) return temp; // Возврат временного объекта } Vector Vector::operator -- (int n) // n - фиктивный параметр { // Уменьшение всех компонент вектора // на единицу (постфикс) Vector temp(*this); // Создание временного объекта и // инициализация его текущим объектом // (объектом, для которого вызвалась функция) for(int i = 0; i < size; i++)// Уменьшение компонент вектора на единицу vect[i]--; // (для текущего объекта) return temp; // Возврат временного объекта } double& Vector::operator [] (int n) { // Перегруженный оператор индексации // для проверки выхода за границы массива if(n < 0) // В случае если индекс меньше нуля, // то возвращаем нулевой элемент массива { cout << "Index of array too small:\tuse zeroth element\n"; return vect[0]; } else if(n > size - 1) // В случае если индекс больше индекса // последнего элемента массива, // то возвращаем последний элемент массива { cout << "Index of array too big:\tuse last element\n"; return vect[size - 1]; } else return vect[n]; // Возврат заданного элемента массива } Vector& Vector::operator + () { // Перегруженный унарный + return *this; } Vector Vector::operator - () { // Перегруженный унарный - Vector temp(*this); // Создание временного объекта и // инициализация его текущим объектом // (объектом, для которого вызвалась функция) for(int i = 0; i < size; i++) temp.vect[i] = -vect[i]; return temp; // Возврат временного объекта } Vector Vector::operator + (const Vector& v) { // Сложение двух векторов с помощью // перегруженного оператора бинарный + if(size == v.size) // Если размерности векторов совпадают { Vector temp(size); // Создание временного объекта for(int i = 0; i < size; i++) temp.vect[i] = vect[i] + v.vect[i]; return temp; // Возврат временного объекта } else // Если размерности векторов не совпадают { cout << "Different arrays sizes !!!\nArray is truncating...\n"; // Урезаем размерность большего вектора int s = (size < v.size) ? size : v.size; Vector temp(s); // Создание временного объекта for(int i = 0; i < s; i++) temp.vect[i] = vect[i] + v.vect[i]; return temp; // Возврат временного объекта } } Vector Vector::operator + (double d) { // Сложение вектора с числом Vector temp(*this); // Создание временного объекта и // инициализация его текущим объектом // (объектом, для которого вызвалась функция) for(int i = 0; i < size; i++) temp.vect[i] += d; return temp; // Возврат временного объекта } Vector& Vector::operator += (const Vector& v) { // Перегруженный оператор += // для сложения двух векторов *this = *this + v; // Вызов функции this->operator=(this->operator+(v)); return *this; } Vector& Vector::operator += (double d) { // Перегруженный оператор += // для сложения вектора с числом *this = *this + d; // Вызов функции this->operator=(this->operator+(d)); return *this; } Vector Vector::operator - (const Vector& v) { // Вычитание двух векторов с помощью // перегруженного оператора бинарный - if(size == v.size) // Если размерности векторов совпадают { Vector temp(size); // Создание временного объекта for(int i = 0; i < size; i++) temp.vect[i] = vect[i] - v.vect[i]; return temp; // Возврат временного объекта } else // Если размерности векторов не совпадают { cout << "Different arrays sizes !!!\nArray is truncating...\n"; // Урезаем размерность большего вектора int s = (size < v.size) ? size : v.size; Vector temp(s); // Создание временного объекта for(int i = 0; i < s; i++) temp.vect[i] = vect[i] - v.vect[i]; return temp; // Возврат временного объекта } } Vector Vector::operator - (double d) { // Вычитание числа из вектора Vector temp(*this); // Создание временного объекта и // инициализация его текущим объектом // (объектом, для которого вызвалась функция) for(int i = 0; i < size; i++) temp.vect[i] -= d; return temp; // Возврат временного объекта } Vector& Vector::operator -= (const Vector& v) { // Перегруженный оператор -= // для вычитания двух векторов *this = *this - v; // Вызов функции this->operator=(this->operator-(v)); return *this; } Vector& Vector::operator -= (double d) { // Перегруженный оператор -= // для вычитания числа из вектора *this = *this - d; // Вызов функции this->operator=(this->operator-(d)); return *this; } double Vector::operator * (const Vector& v) { // Умножение двух векторов с помощью // перегруженного оператора бинарное * double n = 0.0; if(size == v.size) // Если размерности векторов совпадают { for(int i = 0; i < size; i++) n += vect[i] * v.vect[i]; // Вычисляем произведение return n; // Возвращаем произведение } else // Если размерности векторов не совпадают { cout << "Different arrays sizes !!!\nArray is truncating...\n"; // Урезаем размерность большего вектора int s = (size < v.size) ? size : v.size; for(int i = 0; i < s; i++) n += vect[i] * v.vect[i]; // Вычисляем произведение return n; // Возвращаем произведение } } Vector Vector::operator * (double d) { // Умножение вектора на число Vector temp(*this); // Создание временного объекта и // инициализация его текущим объектом // (объектом, для которого вызвалась функция) for(int i = 0; i < size; i++) temp.vect[i] *= d; return temp; // Возврат временного объекта } Vector& Vector::operator *= (double d) { // Перегруженный оператор *= // для умножения вектора на число *this = *this * d; // Вызов функции this->operator=(this->operator*(d)); return *this; } int Vector::GetSize() { // Функция, возвращающая размерность вектора return size; } #include <stdarg.h> Vector& Vector::operator () (unsigned count, ...) { // Если нет элементов if(count == 0) { return *this; } // Удаляем старый вектор delete [] vect; // Создаем новый вектор size = count; vect = new double[size]; double argument; int i = 0; // Создаем список va_list list; // Инициализируем список адресом первого переданного функции параметра va_start(list, count); // Перебираем аргументы while(i < size) { // Получаем следующий элемент // Типы данных у переданных и извлекаемых аргументов должны совпадать argument = va_arg(list, double /* !!! */); // Записываем данные в массив vect[i++] = argument; } // Закрываем список va_end(list); return *this; } Использование класса Vector: #include <iostream.h> #include "Vector.h" void main() { Vector v(4); // Создание вектора cin >> v; // Ввод компонент вектора cout << !--(v*5) << endl; // Вывод длины заданного вектора // Задание вектора из 10 элементов v(10 /* Количество аргументов */, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 /* Все переменные типа double !!! */); // Вывод заданного вектора cout << v << endl; } | |
Просмотров: 3446 | Рейтинг: 0.0/0 |
Всего комментариев: 0 | |