2013 10 29_cpp_lecture_07
description
Transcript of 2013 10 29_cpp_lecture_07
Лекция 7. Namespace.
Переопределение операторов
Valery Lesin. C++ Basics, 2013 1
namespace
• Задает именованное пространство имен
• Позволяет избежать конфликты имен
• Может быть вложенным
• В отличие от классов, может расширяться
Valery Lesin. C++ Basics, 2013 2
1.
2.
3.
4.
5.
6.
7.
8.
9.
namespace std
{
void sort(/*...*/){/*...*/}
}
namespace std
{
void for_each(/*...*/){/*...*/}
}
Объявление и использование
namespace’ов.
Valery Lesin. C++ Basics, 2013 3
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
namespace std
{
void sort(/*...*/);
}
namespace std
{
void sort(/*...*/) {/*...*/}
}
// or even better(why?):
void std::sort(/*...*/){/*...*/}
// usage:
void foo()
{
int a [10] = {1, 2, 3, 4, /*...*/};
std::sort(a, a + 10);
}
using директива
• Можно раскрыть пространство имен:
Valery Lesin. C++ Basics, 2013 4
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
namespace std
{
void sort(/*...*/);
struct vector{/*...*/};
}
void process()
{
using namespace std;
vector v;
sort(v.begin(), v.end());
}
using объявление
• А можно вносить лишь то, что нужно:
Valery Lesin. C++ Basics, 2013 5
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
void process()
{
using std::sort;
using std::vector;
vector v;
sort(v.begin(), v.end());
}
///////////////////////////////////////////////////////////////////
///////
// operations like on sets
namespace A { void foo(); /*...*/ }
namespace B { void foo(); /*...*/ }
namespace C
{
using namespace A;
using namespace B;
using A::foo();
}
Поиск Кёнига (ADL)• Позволяет найти функцию в пространстве имен
одного из ее аргументов (крайне полезно для операторов).
Valery Lesin. C++ Basics, 2013 6
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
namespace long_numbers
{
struct lint{/*...*/};
lint& operator+=(lint&, int);
}
void process()
{
// --- 1 ---
std::vector v;
// don't need to write std::sort
sort(v.begin(), v.end());
// --- 2 ---
long_numbers::lint i;
i+= 5;
//without Argument dependent name lookup:
long_numbers::operator+=(i, 5);
}
Перегрузка операторов
• Традиционный интерфейс для объектов из предметной области, особенно математики
• Сохраняйте естественную семантику. Для класса rectangle::operator+(int) может увеличить его размер, а может покомпонентно сдвинуть – здесь лучше именованная функция.
• Если есть a @= b, то программисты ожидают и a@b и b@a.
Valery Lesin. C++ Basics, 2013 7
Что можно и нельзя?
• Можно перегружать почти все операторы
(кроме :: ; .* ; , ; ?:)
• Нельзя определить новую лексему
оператора. Например a**b вместо pow(a,
b). Может это a*(*b)?
• Нельзя изменить приоритет. Если
point::operator^ - векторное умножение,
то p1 ^ p2 + p3 это p1 ^ (p2 + p3)
Valery Lesin. C++ Basics, 2013 8
Что можно и нельзя? (part 2)
• Если есть a@b и a=b, то само a@=b не
появится. Аналогично наличие оператора
a==b не сделает a!=b. Поможет
boost::operators
• Нельзя изменить количество операндов
• Нельзя переопределить операторы, в
которых участвуют только встроенные типы
Valery Lesin. C++ Basics, 2013 9
Где и как писать операторы?
• Объявление оператора начинается со слова operator
• Можно вызвать как обычную функцию
• Можно объявлять как member, свободную или дружественную функцию
Valery Lesin. C++ Basics, 2013 10
1.
2.
3.
4.
5.
6.
T T::operator+(T const& other);
//...
T a, b;
a + b;
a.operator+(b);
Примеры объявления операторов
Valery Lesin. C++ Basics, 2013 11
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
struct lint
{
lint& operator++();
lint operator++(int);
lint& operator+=(lint const&);
lint operator+ (lint const&);
int operator[](size_t index) const;
};
// or
lint& operator++(lint&);
lint operator++(lint&, int);
lint& operator+=(lint&, lint const&);
lint operator+ (lint const&, lint const&);
int operator[](const lint&, size_t index); // error!
Оператор a@b через a@=b
Valery Lesin. C++ Basics, 2013 12
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
struct string
{
string& operator+=(const char*);
};
string operator+(string, const char*);
/////////////////////////////////////////////////////////////////
string& string::operator+=(const char* str)
{
//impl ...
return *this;
}
string operator+(string lhs, const char* rhs)
{
return lhs += rhs;
}
// or even better
string operator+(string const& lhs, const char* rhs)
{
string tmp;
tmp.reserve(lhs.size() + strlen(rhs));
return (tmp += lhs) += rhs;
}
Предопределенный смысл операторов
• У операторов =; &; , есть
предопределенный смысл. Но и их можно
переопределить или даже закрыть
Valery Lesin. C++ Basics, 2013 13
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
struct file
{
// impl ...
private:
file(file const&);
file& operator=(file const&);
};
//
file a(/*...*/), b(/*...*/);
a = b; // error!
Явное и неявное преобразование1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
struct my_int
{
explicit my_int(int);
operator int();
};
struct my_double
{
my_double(double);
explicit operator double(); // C++11
};
void foo(my_int const&);
void bar(double);
//
foo(5); // error
bar(double(my_double(5.))); // ok
// never mix implicit constructor and operator
// my_int + my_int
// or
// int + int ?
my_int(5) + 6; // error, ambiguous
Valery Lesin. C++ Basics, 2013 14
Смешанная арифметика• Есть string s, хотим иметь возможность
писать s < "a", "a" < s, s < s. Как?
Valery Lesin. C++ Basics, 2013 15
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
// way 1 (lazy):
string::string(const char*); // implicit
operator<(string const&, string const&);
// way 2 (optimal):
bool less(const char*, const char*);
operator<(string const& lhs, const char* rhs)
{ less(lhs.c_str(), rhs); }
operator<(const char*lhs, string const& rhs)
{ less(lhs, rhs.c_str()); }
operator<(string const&, string const&);
{ less(lhs.c_str(), rhs.c_str()); }
Friend функции
• Member-функции:
1. Доступ к private
2. В области видимости класса
3. Имеют неявный this
• static – 1 и 2
• friend – только 1
• friend должны быть объявлены прежде в обрамляющей класс области видимости или иметь параметр класса
• Объявлять можно и в public и в private
• Можно сделать friend целиком класс (все его функции)
Valery Lesin. C++ Basics, 2013 16
Пример friend operator’a
Valery Lesin. C++ Basics, 2013 17
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
struct lint
{
friend std::ostream& operator<<
(std::ostream& os, lint const& i);
private:
std::vector<int> data_;
};
std::ostream& operator<<(std::ostream& os, lint const& i)
{
//impl...
return os;
}
Префиксный и постфиксный инкремент
Valery Lesin. C++ Basics, 2013 18
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
struct iterator
{
// impl...
iterator& operator++();
private:
T* ptr_;
};
iterator& iterator::operator++()
{
++ptr_;
return *this;
}
iterator operator++(iterator& it, int)
{
iterator tmp(it);
++it;
return tmp;
}
Функторы
• Очень удобны для реализации callback’ов и visitor’ов
Valery Lesin. C++ Basics, 2013 19
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
struct rotation
{
rotation(double angle);
void operator()(point& p);
private:
double angle_;
};
void rot_points(vector<point>& vec, double a)
{
for_each(vec.begin(), vec.end(), rotation(a));
}
Операторы для указателя
Valery Lesin. C++ Basics, 2013 20
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
template<class T>
struct smart_ptr
{
T* operator->() { return ptr_; }
T& operator[](size_t i) { return ptr_[i];}
T& operator* () { return *ptr_; }
private:
T* ptr_;
};
struct X {void foo();};
int main()
{
smart_ptr<X> px;
px->foo();
return 0;
}
Какими делать функции?
• Если функция – один из операторов =; ->; []; () делаем их членами (нет выбора)
• Иначе
– если
1. функция требует левый аргумент иного типа (<<)
2. требует преобразования типа для левого аргумента,
3. можно реализовать только через открытый интерфейс класса(!),
– делайте ее не членом класса (возможно, в (1) и (2) – друзьями)
• Иначе, сделайте ее функцией-членом.
Valery Lesin. C++ Basics, 2013 21
Вопросы?
Valery Lesin. C++ Basics, 2013 22