430 likes | 603 Views
Массив объектов. // 1 Rectangle rectangles[5]; // 2 Rectangle * rectangles = new Rectangle [5]; ... delete [] rectangles; // 3 Rectangle * * rectangles = ?. const int count = 5; Rectangle** rectangles = new Rectangle*[count]; for (int i=0; i<count; i++) {
E N D
Массив объектов // 1 Rectanglerectangles[5]; // 2 Rectangle* rectangles = newRectangle[5]; ... delete[] rectangles; // 3 Rectangle**rectangles = ?
constintcount = 5; Rectangle** rectangles = new Rectangle*[count]; for (int i=0; i<count; i++) { rectangles[i] = new Rectangle(); } ... rectangles[0]->set(3, 5); ... for (int i=0; i<count; i++) { delete rectangles[i]; } delete[] rectangles;
#include<vector> • #include<iostream> • int main() • { • std::vector<Rectangle> v; • Rectangle r; • v.push_back(r); • std::cout << v[0].GetSquare(); • return 0; • }
Модификатор const constintx = 5; x = 6; // Ошибка Стиль С: #define PI 3.1415 Стиль С++: constdouble PI = 3.1415;
inti = 0, j = 0; Указатель на константную переменную const int* pi = &i; (*pi) = 0; pi= &j; Константный указатель на переменную int* const pi = &i; (*pi) = 1; pi = &j; Константный указатель на константную переменную const int* const pi = &i; (*pi) = 1; pi = &j;
Приведения типов Неявное – осуществляется компилятором Явное – осуществляется программистом Варианты явного приведения: Корректное преобразование Потеря значащих разрядов Потеря дробной части
void f(double x) { } f(3.5f); doubled = 0; float f = 0; // warning C4244: '=' : conversion from 'double' to 'float', // possible loss of data f = d; // OK d = f;
intwidth = 1024; intheight = 768; floatasp = float(width) / height; floatpi= 3.14; intp= static_cast<int>(pi);
float f = 1.0f; int* n = static_cast<int*>(&f); int* n = reinterpret_cast<int*>(&f); // Ошибка компиляции int i = 0; constint* pI = &i; int* j = const_cast<int*> (pI);
Ссылки • Ссылки используются: • Передача параметров функции • Получение параметров из функции • Псевдонимы Функция обмена переменных на языке С. void Swap(int* a, int* b) { int t = *a; *a = *b; *b = t; } ... Swap(&x, &y); ....
Функция обмена переменных на языке С++ void Swap(int&a, int&b) { inttmp = a; a = b; b = tmp; } intx = 7, y = 10; Swap(x, y);
int& func() { int a; . . . return a; //ОШИБКА }
struct Line { floatx1; floaty1; floatx2; floaty2; }; boolIsIntersect(Line l1, Line l2) {...} boolIsIntersect(Line*l1, Line*l2) {...} boolIsIntersect(Line& l1, Line& l2){...} boolIsIntersect(const Line& l1, constLine& l2){...}
Временные объекты • std::string& f() • { • std::stringstr = "abc"; • returnstr; • } • int main() • { • std::cout << f(); • return 0; • }
std::stringf() • { • std::stringstr = "abc"; • returnstr; • } • int main() • { • std::cout << f(); • return 0; • }
std::string f() • { • std::stringstr = "abc"; • returnstr; • } • int main() • { • std::string& s = f(); • std::cout << s; • return 0; • }
Способы обработки ошибок • Игнорировать • Выводить сообщение • Возвращать int • Возвращать bool • Assert • Try/Catch
Assert (c-style) #include<cassert> intx=0, y=0; std::cin >> x >> y; assert(y != 0); intz = x / y;
Недостатки • void f1() {/* тут могут возникнуть ошибки */} • void f2() {/* тут могут возникнуть ошибки */} • void f3() {/* тут могут возникнуть ошибки */} • int main() • { • f1(); • f2(); • f3(); • // >>> Как обработать все ошибки здесь? <<< • return 0; • }
Try/Catch • try • { • // код, где возможно исключение • } • catch(std::exception& e) • { • // обработчик исключения • } • Система обработки исключительных ситуаций: • предназначена для обработки стандартных и пользовательских исключений • позволяет обрабатывать ошибки не в том месте, где они возникли • не предполагает дальнейшее выполнение программы
Bad_alloc • try • { • double* p = newdouble[2000000000]; • } • catch(conststd::bad_alloc& ex) • { • std::cerr << ex.what(); • }
Стандартные классы исключений exception logic_error runtime_error length_error range_error bad_cast bad_alloc domain_error bad_exception bad_typeid overflow_error out_of_range io_base::failure underflow_error invalid_argument
Выбрасывание исключения (throw) Вариант 1: использовать простой тип • try • { • if (y == 0) throwstd::string("Деление на ноль!"); • z = x / y; • } • catch(conststd::string& ex) • { • std::cerr << ex; • }
Вариант 2: класс std::exception • try • { • if (y == 0) throwstd::invalid_argument("Деление на ноль!"); • z = x / y; • } • catch(std::exception& ex) • { • std::cerr << ex.what(); • }
Вариант 3: собственный класс • classExceptionDivideByZero: publicstd::exception • { • }; • try • { • if (y == 0) throwExceptionDivideByZero(); • z = x / y; • } • catch(ExceptionDivideByZero) • { • std::cerr<< "Деление на ноль!"; • }
#include<stdexcept> • classTime • { • intm_hour; • intm_min; • intm_sec; • public: • Time(inthour, intmin, intsec) • { • if (hour < 0 || hour > 59) • throwstd::invalid_argument("Hour must be between 0..59"); • ... • } • };
Catchall • try • { • } • catch(...) • { • std::cerr << "Неизвестная ошибка!"; • }
Catch-цепочка try { } catch(std::bad_alloc) { } catch(std::bad_cast) { }
try { } catch(std::exception) { } catch(...) { } catch(std::bad_alloc) { } // ОШИБКА
try { } catch(std::bad_alloc) { } catch(std::exception) { } catch(...) { } // ВЕРНО
Повторное выбрасывание исключения • try • { • try • { • // Здесь произошла ошибка выделения памяти • } • catch(std::bad_alloc) • { • // Выдаем сообщение, и перевыбрасываем: • throw; • } • } • catch(std::exception) • { • // Заносим в лог • }
Конструктор При выбросе исключения в конструкторе процесс конструирования экземпляра класса прерывается и он считается не созданным. Деструктор для такого класса вызван не будет. Будут вызваны деструкторы для тех полей класса, для которых успели выполниться конструкторы. Деструктор Деструкторы не должны возвращать исключений. Если в деструкторе возникает исключение, оно должно быть обработано в нем же. Задача про 10 объектов
classB • { • public: • B() { std::cout << "1"; } • ~B() { std::cout << "2"; } • }; • class C • { • B b; • public: • C() { throw 0; std::cout << "3"; } • ~C() { std::cout << "4"; } • }; • ------------------------ • try • { • C c; • } • catch(...) • { • }
Модификатор static Инициализация static-переменной: -если объявлена глобально, инициализируется при первом запуске программы. -если локально, то при первом запуске функции. -по умолчанию, static-переменная инициализируется нулем. intf() { static intiCounter = 0; return(++iCounter); } void main() { for (inti=0, t; i<10; i++) t = f(); std::cout << f() << std:: endl; } Переменные с модификатором static видны только в пределах функции объявления,но сохраняют свое значение между вызовами.
std::stringGetSynonym(std::stringword) { LoadBase(); ... }
std::stringGetSynonym(std::stringword) { staticboolisLoad = false; if(!isLoad) { LoadBase(); isLoad= true; } ... }
Статические методы classPoint { double x; double y; public: Point(doublex, double y) { this->x = x; this->y = y; } doubleDistanceTo(const&Pointpt) { returnstd::Sqrt((pt.x-x) * (pt.x-x) + (pt.y-y) * (pt.y-y)); } }; Point*p1 = newPoint(21.28, 49.32); Point*p2 = newPoint(81.12, 37.93); doubledist = p1->DistanceTo(*p2);
classPoint { public: doubleDistance(const&Pointp1, const&Pointp2) { returnstd::sqrt( (p2.x-p1.x) * (p2.x-p1.x) + (p2.y-p1.y) * (p2.y-p1.y) ); } } Point p1(21.28, 49.32); Point p2(81.12, 37.93); doubledist= ?
classPoint { public: staticdoubleDistance(const&Pointp1, const&Pointp2) { returnstd::sqrt( (p2.x-p1.x) * (p2.x-p1.x) + (p2.y-p1.y) * (p2.y-p1.y) ); } } Point p1(21.28, 49.32); Point p2(81.12, 37.93); doubledist = Point::Distance(p1, p2);
Статические данные • #include “Foo.h” • intFoo::b = 0; • Foo::Foo() • : a(0) • { • b++; • } • intFoo::GetA() • { • returna; • } • intFoo::GetB() • { • returnb; • } • classFoo • { • int a; • staticintb; • public: • Foo(); • intGetA(); • staticintGetB(); • }; • int main() • { • Foo f, f2; • std::cout << f.getA(); • std::cout << Foo::getB(); • return 0; • }
1. Static-данные существуют в единственном экземпляре для всех объектов данного класса. 2. Static-данные требуют повторного объявления вне класса (в файле методов). 3. К static-данным имеют доступ все методы данного класса.