Неперегружаемые операторы
Индексирование
Преобразование
complex::operator double() const
{
return (m_re*m_re-m_im*m_im);
}
// вместо
double complex::norm() const
{
return (m_re*m_re-m_im*m_im);
}
double& matrix::operator() (int i,int j)
{
return (p[i][j]); // или p[i*size+j];
}
Операторы ввода/вывода
Перегрузку операторов ввода/вывода приходится оформлять в виде дружественных функций класса. При использовании оператора ввода или вывода слева от него должен находиться экземпляр потока и ничто иное. То есть перегруженные операторы ввода/вывода являются членами потоков, а не других классов. Вмешаться во внутреннюю реализацию потоков мы не можем. Но можно использовать функции, которые не являются членами классов, но позволяют получить доступ к их скрытым (private) членам.
friend ostream& operator<< (ostream& out, complex x);
friend istream& operator<< (istream& out, complex x);
ostream& operator<< (ostream& out, complex x)
{
return (out<<”(“<<x.m_re<<”,”<<x.m_im<<”)”);
}
istream& operator>>(istream& out, complex x)
{
return (in>>x.m_re>>x.m_im);
}
Не могут быть перегружены операторы следующие:
- :: (левый и правый операнд являются не значениями, а именем)
- . (правый операнд является именем)
- .* (правый операнд является именем)
- ?: (арифметический оператор имеет специфическую семантику)
- new (операнд является именем, кроме того выполняет небезопасную процедуру)
- delete (не используется без new, кроме того выполняет небезопасную процедуру)
С помощью механизма перегрузки можно переопределить только существующие операторы. Новые операторы определить невозможно.
Объекты, у которых перегружен оператор вызова функций operator().
В файле <functional> уже определено несколько полезных арифметических и других объектов-функций:
- plus сложение
- minus вычитание
- multipies умножение
- divides деление
- modulus деление по модулю
- negate отрицание
int main(int argc, char* argv[])
{
vector<int> v(10);
...
vector<int>::iterator i=v.begin();
while(i!= v.end())
{
*i = -(*i);
i++;
}
transform(v.begin(),v.end(), v.begin(), negate<int>()); // вместо 6 строк одна
}
Программисты могут определить свои объекты-функции:
template <class PAR>
class Rand: public unary_function<PAR, void>
{
public:
explicit Rand(int n) { srand (n); }
void operator() (PAR& i) { i=(PAR)rand(); }
};
int main(int argc, char* argv[])
{
vector<int> v(10);
vector<int>::iterator i=v.begin();
while(i!= v.end())
{
*i = rand();
i++;
}
for_each(v.begin(), v.end(), Rand<int>(5)); // вместо 6 строк одна
// если не считать объявления объекта-функции, которое впрочем будет многократно использоваться и окупится
}
Предикаты позволяют без изменения шаблона изменять критерии сравнения элементов контейнера и другие подобные действия. У предикатов объект-функция возвращает значение bool. В файле <functional> уже определено несколько полезных предикатов:
- equal_to бинарный предикат равенства
- not_equal_to бинарный предикат неравенства
- greater бинарный предикат >
- less бинарный предикат < (используется по умолчанию)
- greater_equal бинарный предикат >=
- less_equal бинарный предикат <=
- logical_and бинарный предикат И
- logical_or бинарный предикат ИЛИ
- logical_not унарный предикат НЕ
int main(int argc, char* argv[])
{
vector<int> v(10);
for_each(v.begin(), v.end(), Rand<int>(5));
// sort(v.begin(), v.end());
// reverse(v.begin(), v.end());
sort(v.begin(), v.end(), greater<int>());
}
Аналогично программисты могут определить свои предикаты:
class InRange: public unary_function<int, bool>
{
int m_left, m_right;
public:
explicit InRange(int left, int right): m_left(left), m_right(right) {}
bool operator() (const int& i) { return (i>m_left && i<m_right); }
};
int main(int argc, char* argv[])
{
vector<int> v(10);
for_each(v.begin(), v.end(), Rand<int>(1000));
vector<int>::iterator i=v.begin();
cout << count_if(v.begin(), v.end(), InRange(1000,10000));
return 0;
}