2vcTnguyvU
.pdfПо умолчанию сортировка ассоциативных контейнеров производится с помощью операции “меньше”. Однако можно указать и другой оператор сравнения (объекты-функции).
1.Используя обобщенный алгоритм generate, заполнить значениями вектор целых чисел. Причем, при заполнении сгенерированное значение получить с помощью определенной функции, которая выбирает только простые числа. Затем, используя алгоритм random_shuffle расположить элементы в случайном порядке. Затем, заполнить другой вектор целых чисел, используя алгоритм random_shuffle случайными числами. После этого, используя алгоритм transform заполнить третий вектор значениями, полученными сложением элемента первого вектора с удвоенным значением 2-вектора. Удвоение значения элемента второго вектора производить, если этот элемент нечетный. Все результаты выводить на экран. Использовать STL.
2.Применить алгоритмы accumulate и inner_product для нахождения уравнения линии регрессии у = а + bx для данных находящихся в файле в виде (x, y)
20.5118.1
20.6118.25
20.65 118.2
20.75 118.4
20.8118.4
20.85118.5
20.9118. 45
21.0118.5
Используйте метод наименьших квадратов. Алгоритм accumulate вычисляет
значение ∑xI и значение ∑y I ; |
|
Алгоритм inner_product вычисляет ∑x2 |
I и ∑xI * y I . Результаты расчетов |
поместить в третий столбец, результат на экран, вывод данных представляет уравнение регрессии и три столбца данных: два столбца входных данных и третий столбец - результат расчета.
a*n+b*∑xI =∑y I
a*∑xI +b*∑x2 I = ∑xI * y I .
3. Создайте приложение, использующее контейнер map. Специализируйте этот контейнер так: ключом является тип string -фамилия , а значением – вектор с названиями стран, которые посетил данный гражданин. Поместите в отображение(map) как минимум пять элементов. Реализуйте возможность делать запрос по фамилии, добавлять новые страны, распечатывать содержимое.
120
4. Перепишите программу текстового поиска с использованием multimap для хранения позиций слов.
Контрольные вопросы
1.Объясните разницу между размером и емкостью контейнера. Почему понятие емкости необходимо для контейнера, содержащего элементы в непрерывной области памяти, и не нужно для списка?
2.Почему большие сложные объекты удобнее хранить в контейнере в виде указателей на них, а для коллекции целых чисел применение указателей снижает эффективность? Докажите программным путем.
3.Какие ошибки допущены при использовании итераторов:
const vector<int> ivec; vector<string> svec; list<int> ilist;
(a)vector<int>::iterator it=ivec.begin();
(b)list<int>::iterator it=ilist.begin()+2;
(c)vector<string>::iterator it=&svec[0];
(d)for(vector<string>::iterator it=svec.begin();it!=0; ++it)
4.Приведите по два примера когда нужно использовать шаблонные классы set и map.
5.Напишите определение объектов map и set.
Задание для самостоятельной работы
1. Разработайте тестирующую программу, которая выполняет простую проверку наличия функций-членов и типов и их правильного поведения для одной специализации шаблонного класса map
#include <assert.h> #include <iostream> #include <functional> #include <map> using namespace std; void test_map()
{
typedef allocator<int> Myal; typedef less<char> Mypred; typedef pair<const char, int> Myval;
typedef map<char, int, Mypred, Myal> Mycont; Myval x, xarr[3], xarr2[3];
for (int i=0; i<3; i++)
{new (&xarr[i]) Myval('a'+i, 1+i); 121
new (&xarr2[i]) Myval('d'+i, 4+i);
}
Mycont::key_type *p_key=(char *)0; Mycont::mapped_type *p_mapped=(int *)0; Mycont::key_compare *p_kcomp=(Mypred *)0; Mycont::allocator_type *p_alloc=(Myal *)0; Mycont::value_type *p_val=(Myval *)0; Mycont::value_compare *p_vcomp=0; Mycont::pointer p_ptr=(Myval *)0; Mycont::const_pointer p_cptr=(const Myval *)0; Mycont::reference p_ref=x; Mycont::const_reference p_cref=(const Myval&)x; Mycont::size_type *p_size=(size_t *)0; Mycont::difference_type *p_diff=(ptrdiff_t *)0; Mycont v0;
Myal al=v0.get_allocator(); Mypred pred;
Mycont v0a(pred), v0b(pred, al); assert(v0.empty() && v0.size()==0); assert(v0a.size()==0 && v0a.get_allocator()==al); assert(v0b.size()==0 && v0b.get_allocator()==al); Mycont v1(xarr, xarr+3);
assert(v1.size()==3 && (*v1.begin()).first=='a'); Mycont v2(xarr, xarr+3, pred); assert(v2.size()==3 && (*v2.begin()).first=='a'); Mycont v3(xarr, xarr+3, pred, al); assert(v3.size()==3 && (*v3.begin()).first=='a'); const Mycont v4(xarr, xarr+3); assert(v4.size()==3 && (*v4.begin()).first=='a'); v0=v4;
assert(v0.size()==3 && (*v0.begin()).first=='a'); assert(v0.size() <=v0.max_size()); Mycont::iterator p_it=v1.begin(); Mycont::const_iterator p_cit=v4.begin(); Mycont::reverse_iterator p_rit=v1.rbegin(); Mycont::const_reverse_iterator p_crit=v4.rbegin(); assert((*p_it).first=='a' && (*p_it).second==1
&& (*--(p_it=v1.end())).first=='c'); assert((*p_cit).first=='a' && (*--(p_cit=v4.end())).first=='c'); assert((*p_rit).first=='c' && (*p_rit).second==3
122
&& (*--(p_rit=v1.rend())).first=='a'); assert((*p_crit).first=='c' && (*--(p_crit=v4.rend())).first=='a'); v0.clear();
pair<Mycont::iterator, bool> pib=v0.insert(Myval('d', 4)); assert((* pib.first).first=='d' && pib.second); assert((*--v0.end()).first=='d'); pib=v0.insert(Myval('d',5));
assert((*pib.first).first=='d' && (*pib.first).second==4 && !pib.second); assert((*v0.insert(v0.begin(), Myval('e',5))).first=='e');
v0.insert(xarr, xarr+3);
assert(v0.size()==5 && (*v0.begin()).first=='a'); v0.insert(xarr2, xarr2+3);
assert(v0.size()==6 && (*--v0.end()).first=='f'); assert(v0['c']==3);
v0.erase(v0.begin()); assert((*v0.begin()).first=='b' && v0.size()==5); v0.erase (v0.begin(), ++v0.begin()) ;
assert( v0.size()==4);
assert(v0.erase ('x')==0 && v0.erase('e')==1); v0.clear();
assert(v0.empty());
v0.swap(v1);
assert(!v0.empty() && !v1.empty()); swap(v0,v1);
assert(v1==v1 && v0<v1);
assert(v0.key_comp()('a','c') && !v0.key_comp()('a','a')); assert(v0.value_comp() (Myval('a',0), Myval('e', 1))
&& !v0.value_comp() (Myval('a', 0), Myval('a',1))); assert((*v4.find('b')).first=='b');
assert(v4.count('x')==0 && v4.count('b')==1); assert((*v4.lower_bound('a')).first=='a'); assert((*v4.upper_bound('a')).first=='b'); pair<Mycont::const_iterator, Mycont::const_iterator> pcc=v4.equal_range('a');
assert((*pcc.first).first=='a' && (*pcc.second).first=='b');
}
#pragma argsused int main()
{
test_map();
123
cout<<"success testing";
cout << "Press key 1 !! Good by!!"<< endl; while (m!='1')
cin>>m; return 0;
}
Тестовое задание
Шаблоны классов
1.Выберите наиболее подходящий из указанных шаблонов:
template |
<class T1, class T2, int J> class A { }; |
//(1) |
template |
<class T, int J> class A<T, T*, J> { }; |
//(2) |
template |
<class T1, class T2, int J> class A<T1*, T2, J> { };//(3) |
|
template <class T> class A<int, T*, 5> {}; |
//(4) |
|
template |
<class T1, Class T2, int J> class A<T1, T2*, J> { }; //(5) |
(т.е. укажите какой шаблон используется в следующих вызовах, укажите неоднозначность, если она имеется))
A<int, int, 1> a1; A<int, int*, 1> a2; A<int, char*, 5> a3; A<int, char*, 1> a4; A < int*, int*, 2> a5;
2. В следующей функции используются необязательные временные объекты как минимум в трех местах. Сколько таких мест найдете вы? string FindAddr( list<Employee> emps, string name) {
for(list<Employee>::iterator |
i=emps.begin(); i!=emps.end(); i++) { |
|
if(*i==name) |
{ |
return i ->addr; } |
} return “”; } |
|
|
Как должен быть сконструирован класс Employee, чтобы этот код работал? Доработайте программу. Примените соответствующую функцию из стандартной библиотеки. Почему не рекомендуется использовать временные объекты, а что использовать тогда ?
3. Имеется шаблон класса Stack: template <class T> class Stack {
public: |
|
|
Stack(); |
~Stack(): |
|
Stack & operator=(const Stack&); |
||
size_t |
Count() const; |
|
void Push(const T & ); T Pop(); |
||
private: |
|
|
T* |
v_; |
//указатель на область памяти, достаточную для |
|
|
124 |
size_t vsize_; // размещения vsize_ объектов типа T
size_t vused_; //количество реально используемых объектов };
При реализации конструктора копирования и оператора копирующего присваивания для управления распределением памяти была разработана вспомогательная функция:
template <class T> T* NewCopy ( const T* src, size_t srcsize, size_t destsize )
{assert (destsize>=srcsize); T* dest= new T[destsize]; try {
copy( src, src+srcsize, dest );
}catch (...)
{delete [] dest;
throw; } return dest; }
Приведите реализацию конструкторов, оператора копирования с помощью этой вспомогательной функции.
Наследование
1. Какие ошибки (если таковые есть) имеются в приведенном ниже коде? template <typename T> class X_base {
public:
typedef T instantiated_type; }; template<typename A, typename B> class X: public X_base<B> { public:
bool operator() const instantiated_type & i) const { return i!= instantiated_type(); }
// прочий код };
2. Приведенный шаблон предоставляет функции управления списком, включая возможность работы с элементами списка в определенных позициях.
template <class T> class MyList { public:
bool Insert (const T&, size_t index ); T Access (size_t index ) const; size_t Size() const;
private: T* buf;
125
size_t bufsize_; };
Рассмотрите следующий код, демонстрирующий два способа написания класса MySet с использованием MyList.
(a) template <class T> class MySet1: private MyList<T> { public:
bool Add ( const T & ); |
//вызывает Insert() |
T Get (size_t index ) const; |
//вызывает Access() |
using MyList<T>::Size; |
|
// .... |
|
}; |
|
(b) template <class T> class MySet2 { |
|
public: |
|
bool Add (const T & ); |
//вызывает impl_.insert() |
T Get (size_t index const ); |
|
// вызывает impl_.Access() |
|
size_t Size () const; |
//вызывает impl_.Size () |
// ... |
|
private: |
|
MyList<T> impl_; |
|
}; |
|
Ответьте на следующие вопросы:
a.Имеется ли различие между MySet1 и MySet2?
b.В чем заключается различие между закрытым наследованием и включением? Приведите по возможности более полный список причин, по которым могло бы потребоваться использовать наследование, а не включение.
c.Приведите по возможности более полный список причин, по которым могло бы потребоваться открытое наследование.
d.Создайте программу с использованием классов MySet1 и MySet2.
3. Предположим, что класс Derv является частным производным класса Base. Был определен объект класса Derv, расположенный в функции main(). Через него можно получить доступ к:
членам класса Derv, объявленным как public; членам класса Derv, объявленным как protected; членам класса Derv, объявленным как private; членам класса Base, объявленным как public; членам класса Base, объявленным как protected; членам класса Base, объявленным как private.
126
4. Предположим, что класс Derv является производным класса Base. Оба класса содержат метод func() без аргументов. Напишите выражение, входящее в метод класса Derv, которое вызывает метод func() базового класса.
Абстрактные классы, динамическая информация о типе
1. Рассмотрите следующий пример.
class A { |
public: |
|
|
||
virtual |
~A(); |
|
|
|
|
string Name(); |
|
|
|
||
private: |
|
|
|
|
|
virtual string DoName(); |
}; |
|
|||
class B1 : virtual public A |
{ |
|
|||
string DoName(); |
}; |
|
|
||
class B2 : virtual public A |
|
|
|||
{ |
string DoName(); }; |
|
|||
A::~A() { } |
|
|
|
||
string A::Name() |
{ return DoName(); } |
||||
string A::DoName() { return “A”; |
} |
||||
string B1::DoName() { return “B1”; } |
|||||
string |
B2::DoName () { return “B2”; } |
||||
class D : public B1, public |
B2 { |
|
|||
string |
DoName() |
{ return “D”; } |
}; |
||
Покажите по возможности наилучший способ избежать множественное |
|||||
наследование, написав эквивалентный |
(или максимально приближенный к |
||||
оригиналу) |
class D без использования |
множественного наследования. Каким |
образом можно достичь той же функциональности и применимости класса D при минимальном изменении синтаксиса вызывающего кода?
Классы и динамическая память
1.Какой вариант конструктора по умолчанию предпочтительней:
(a)template <class T> Stack<T>::Stack() : v_(0), vsize_(10), vused_(0)
{v_=new T[vsize_]; //начальное распределение памяти
|
|
} |
(b) |
template <class T> Stack<t>::Stack() |
|
|
: v_(new T[10]), vsize_(10), vused_(0) { } |
|
2. |
Рассмотрите следующий код. Найдите ошибку в этом фрагменте, |
|
|
связанную с управлением памятью. |
|
|
class B |
|
|
{ |
public: |
|
virtual ~B(); |
|
|
|
127 |
void operator delete (void *, size_t ) throw (); void operator delete [] (void *, size_t ) throw (); void f (void*, size_t ) throw (); };
class D: public B {
void operator delete (void *) throw (); void operator delete [](void * ) throw (); };
Почему операторы delete в классе B имеют вторые параметры, а в классе D - нет?
3.Приведенный далее фрагмент кода является продолжением предыдущего. Какой из операторов delete() вызывается в каждом из выражений? Почему, и с какими параметрами?
D* pd1= new D; delete pd1;
B* pb1 = new D; delete pb1;
D* pd2 = new D[10]; delete [] pd2;
B* pb2 = new D[10]; delete [] pb2;
4.Корректны ли два следующих присваивания?
|
B b; |
|
|
|
|
typedef void (B::*PMF)(void* , size_t ); |
|||
|
PMF p1 = &B::f; |
|
|
|
|
PMF p2=& B::operator delete; |
|
||
5. |
Имеются |
ли в следующем коде |
ошибки, связанные с управлением |
|
памятью? |
|
|
|
|
|
class X |
{ |
|
|
|
public: |
|
|
|
|
void * operator new (size_t s, int ) throw (bad_alloc) |
|||
|
{ return ::operator new(s); |
} }; |
|
|
|
|
|
Исключения |
|
1. |
Рассмотрите следующий класс: |
|
||
|
class C : private A { |
B b_; |
}; |
Как в конструкторе класса С можно перехватить исключение , сгенерированное в конструкторе базового подъекта (такого, как А) или объекта-члена (такого, как b_) ?
2. Какие из приведенных инструкций throw ошибочны? Почему? Для правильных инструкций укажите тип возбужденного исключения:
(a) class exceptionType { }; throw exceptionType();
128
(b)int excpObj; throw excpObj;
(c)enum mathErr ( overflow, underflow, zeroDivide }; throw mathErr zeroDivide();
(d)int *pi=excpObj;
throw pi;
Потоковый ввод-вывод
1.Какие классы используются в потоках ввода-вывода?
2.Что из себя представляют манипуляторы? Приведите примеры использования.
3.Определите для вывода манипулятор based с двумя параметрами: система счисления и целое значение, и печатайте целое в представлении, определяемом системой счисления. Например, based(2,9) напечатает 1001.
4.Разработать несколько функций для запроса и чтения данных разных типов. Предложения: целое, вещественное число, имя файла, почтовый адрес, дата, личная информация, и т.п. Попытайтесь сделать их устойчивыми к ошибкам.
Стандартная библиотека шаблонов
1.В приведенном коде имеется, как минимум, четыре ошибки, связанные с использованием итераторов. Укажите найденные ошибки.
int main() { vector<Date> vec;
copy(istream_iterator<Date>(cin), istream_iterator<Date(), back_inserter(vec) );
vector<date.::iterator first =find(vec.begin (), vec.end(), “01/01/10”); vector<Date>::iterator last =find(vec.begin(), vec.end(), “12/31/10”); *last=”12/30/10”;
copy(first, last, ostream_iterator<Date>(cout, “\n”) ); vec.insert (--vec.end(), TodayDate() );
copy(first, last, ostream_iterator<Date>cout, “\n”) ); }
2.Какие ошибки допущены при использовании итераторов:
const vector<int> ivec; vector<string> svec; list<int> ilist;
(a)vector<int>::iterator it=ivec.begin();
(b)list<int>::iterator it=ilist.begin()+2;
(c)vector<string>::iterator it=&svec[0];
(d)for(vector<string>::iterator it=svec.begin();it!=0; ++it)
129