| 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;
}
| |
| Просмотров: 3504 | Рейтинг: 0.0/0 |
| Всего комментариев: 0 | |