Upgrade to Pro — share decks privately, control downloads, hide ads and more …

АФТИ ООП 2013-2014. Лекция II/11

АФТИ ООП 2013-2014. Лекция II/11

Oleg Dashevskii

April 28, 2014
Tweet

More Decks by Oleg Dashevskii

Other Decks in Education

Transcript

  1. КЛАССЫ СВОЙСТВ И ЗНАЧЕНИЙ • Шаблоны позволяют иметь произвольное количество

    аргументов. • Можно настроить любой аспект поведения класса или функции. • Но передавать всегда и везде по 100 аргументов неудобно…
  2. template <typename T>! inline T accum(const T *beg, const T

    *end) {! T total = T(); // T() returns zero value! ! while (beg != end)! total += *beg++;! ! return total;! }! ! ///////! ! int num[] = { 1, 2, 3, 4, 5 };! int avg1 = accum(&num[0], &num[5]) / 5; // 3! ! char name[] = "templates";! int len = sizeof(name) - 1;! int avg2 = accum(&name[0], &name[len]) / len; // -5 WAT
  3. • total имеет тип 8-битный char, которого не хватает для

    суммирования. • Можно тип суммы сделать аргументом шаблона… но это очень неудобно. • Воспользуемся другим подходом.
  4. template <typename T>! class AccumulationTraits;! ! template<>! class AccumulationTraits<char> {!

    public:! typedef int AccT;! };! ! template<>! class AccumulationTraits<short> {! public:! typedef int AccT;! };! ! template<>! class AccumulationTraits<int> {! public:! typedef long AccT;! };! ! // unsigned int -> unsigned long! // float -> double! // .....
  5. template <typename T>! inline AccumulationTraits<T>::AccT! accum(const T *beg, const T

    *end) {! typedef typename AccumulationTraits<T>::AccT AccT;! ! AccT total = AccT(); // AccT() returns zero value! ! while (beg != end)! total += *beg++;! ! return total;! }! ! char name[] = "templates";! int len = sizeof(name) - 1;! int avg2 = accum(&name[0], &name[length]) / len;! // 108
  6. template <typename T>! class AccumulationTraits;! ! template<>! class AccumulationTraits<char> {!

    public:! typedef int AccT;! static const AccT zero = 0;! };! ! template<>! class AccumulationTraits<short> {! public:! typedef int AccT;! static const AccT zero = 0;! };! ! template<>! class AccumulationTraits<int> {! public:! typedef long AccT;! static const AccT zero = 0;! };! ! template <typename T>! inline AccumulationTraits<T>::AccT accum(const T *beg, const T *end) {! typedef typename AccumulationTraits<T>::AccT AccT;! ! AccT total = AccumulationTraits<T>::zero;! ! while (beg != end)! total += *beg++;! ! return total;! } Константа zero
  7. template <typename T>! class AccumulationTraits;! ! template<>! class AccumulationTraits<char> {!

    public:! typedef int AccT;! static AccT zero() { return 0; }! };! ! template<>! class AccumulationTraits<short> {! public:! typedef int AccT;! static AccT zero() { return 0; }! };! ! template<>! class AccumulationTraits<int> {! public:! typedef long AccT;! static AccT zero() { return 0; }! };! ! template <typename T>! inline AccumulationTraits<T>::AccT accum(const T *beg, const T *end) {! typedef typename AccumulationTraits<T>::AccT AccT;! ! AccT total = AccumulationTraits<T>::zero();! ! while (beg != end)! total += *beg++;! ! return total;! } Функция zero()
  8. template <typename T, typename AT = AccumulationTraits<T> >! class Accum

    {! public:! static typename AT::AccT accum(const T *beg, const T *end) {! typename AT::AccT total = AT::zero();! ! while (beg != end)! total += *beg++;! ! return total;! }! };! ! template <typename T>! inline typename AccumulationTraits<T>::AccT accum(const T *beg, const T *end) {! return Accum<T>::accum(beg, end);! }! ! template <typename Traits, typename T>! inline typename Traits::AccT accum(const T *beg, const T *end) {! return Accum<T, Traits>::accum(beg, end);! } •Используем класс Accum для возможности задания аргумента по умолчанию (в C++11 уже не нужно!). •Удобные вспомогательные функции-обертки.
  9. • Вместо того чтобы свойства (типы, константы, …) делать параметрами

    шаблона по T, помещаем их в дополнительный класс свойств (Traits). • Создаем набор полных специализаций Traits для всех нужных T. • Алгоритмы (функции) обычно оборачиваются в классы, чтобы иметь возможность задавать аргументы по умолчанию (до C++11). КЛАССЫ СВОЙСТВ
  10. КЛАССЫ СТРАТЕГИЙ class SumPolicy {! public:! template <typename T1, typename

    T2>! static void accumulate(T1 &total, const T2 &value) {! total += value;! }! };! ! template <typename T,! typename Policy = SumPolicy,! typename Traits = AccumulationTraits<T> >! class Accum {! public:! typedef typename Traits::AccT AccT;! static AccT accum(const T *beg, const T *end) {! AccT total = Traits::zero();! ! while (beg != end) {! Policy::accumulate(total, *beg);! ++beg; ! }! ! return total;! }! }; Операция суммирования 
 вынесена в Policy
  11. template <bool use_compound_op = true>! class SumPolicy {! public:! template

    <typename T1, typename T2>! static void accumulate(T1 &total, const T2 &value) {! total += value;! }! };! ! template <>! class SumPolicy<false> {! public:! template <typename T1, typename T2>! static void accumulate(T1 &total, const T2 &value) {! total = total + value;! }! }; class MultPolicy {! public:! template <typename T1, typename T2>! static void accumulate(T1 &total, const T2 &value) {! total *= value;! }! }; Другая операция Тонкая настройка суммирования
  12. ПРИНЦИП SFINAE class MyClass {};! class MyStruct {};! class MyUnion

    {};! void myfunc() {}! enum E { e1 } e;! ! template <typename T>! bool check() {! return IsClassT<T>::Yes;! }! ! template <typename T>! bool checkT(T) {! return check<T>();! }! ! check<int>() // false! check<MyClass>() // true! check<MyStruct>() // true! check<MyUnion>() // true! checkT(e) // false! checkT(myfunc) // false Substitution Failure Is Not An Error template <typename T>! class IsClassT {! typedef char One;! typedef struct { char a[2]; } Two;! ! template <typename C> static One test(int C::*);! template <typename C> static Two test(...);! public:! enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 };! enum { No = !Yes };! };
  13. МЕТАПРОГРАММИРОВАНИЕ template <int N>! class Pow3 {! public:! enum {

    result = 3 * Pow3<N-1>::result };! };! ! template<>! class Pow3<0> {! public:! enum { result = 1 };! };! ! // Pow3<7>::result => 2187
  14. ВЫЧИСЛЕНИЕ КВАДРАТНОГО КОРНЯ template <int N, int LO = 1,

    int HI = N>! class Sqrt {! public:! enum { mid = (LO + HI + 1) / 2 };! ! enum { result = (N < mid * mid) ? Sqrt<N,LO,mid-1>::result! : Sqrt<N,mid,HI>::result };! };! ! template <int N, int M>! class Sqrt<N,M,M> {! public:! enum { result = M };! }; Проблема: лишние инстанцирования
  15. ! template <int N, int LO = 1, int HI

    = N>! class Sqrt {! public:! enum { mid = (LO + HI + 1) / 2 };! ! typedef typename IfThenElse<(N < mid * mid),! Sqrt<N,LO,mid-1>,! Sqrt<N,mid,HI> >::ResultT SubT;! ! ! enum { result = SubT::result };! };! ! template <int N, int M>! class Sqrt<N,M,M> {! public:! enum { result = M };! };! template <bool C, typename Ta, typename Tb>! class IfThenElse;! ! template <typename Ta, typename Tb>! class IfThenElse<true, Ta, Tb> {! public:! typedef Ta ResultT;! };! ! template <typename Ta, typename Tb>! class IfThenElse<false, Ta, Tb> {! public:! typedef Tb ResultT;! }; Только одно инстанцирование
  16. C++ C class struct new и delete malloc() и free()

    Конструкторы и деструкторы Явные функции инициализации и уничтожения Исключения Коды возврата Виртуальные функции Много функций с разными именами, switch … case Перегрузка функций и манглинг Нет манглинга Чёткая структура классов Модульность, слабая структура внутри каждого модуля
  17. libtiff tiff.h tiffio.h t4.h tif_fax3.h … Типы и 
 структуры


    данных Чтение
 и запись
 файлов
 TIFF
  18. #define ...! #define ...! #define ...! #define ...! ! //

    ...! ! typedef ...! typedef ...! typedef ...! ! typedef struct { } ...! typedef struct { } ...! typedef struct { } ...! ! // ...! ! void func...(...);! void func...(...);! void func...(...);! void func...(...);! ! //! ! extern int var...;! extern int var...; Типичный
 заголовочный
 файл на C
  19. #ifdef __cplusplus! extern "C" {! #endif! ! ! // ........!

    ! ! #ifdef __cplusplus! }! #endif! Непосредственное
 использование
 библиотек на C
 из C++
  20. typedef struct tiff TIFF;! ! // ...! ! extern TIFFTagMethods

    *TIFFAccessTagMethods( TIFF * );! extern void *TIFFGetClientInfo( TIFF *, const char * );! extern void TIFFSetClientInfo( TIFF *, void *, const char * );! ! extern void TIFFCleanup(TIFF*);! extern void TIFFClose(TIFF*);! extern int TIFFFlush(TIFF*);! extern int TIFFFlushData(TIFF*);! extern int TIFFGetField(TIFF*, ttag_t, ...);! extern int TIFFVGetField(TIFF*, ttag_t, va_list);! extern int TIFFGetFieldDefaulted(TIFF*, ttag_t, ...);! extern int TIFFVGetFieldDefaulted(TIFF*, ttag_t, va_list);! extern int TIFFReadDirectory(TIFF*);! extern int TIFFReadCustomDirectory(TIFF*, toff_t, const TIFFFieldInfo[],! size_t);! extern int TIFFReadEXIFDirectory(TIFF*, toff_t);! extern tsize_t TIFFScanlineSize(TIFF*);! extern tsize_t TIFFRasterScanlineSize(TIFF*);! extern tsize_t TIFFStripSize(TIFF*);! extern tsize_t TIFFRawStripSize(TIFF*, tstrip_t);! Маленький кусок из tiffio.h
  21. class TiffWrapper {! public:! TiffWrapper(struct tiff *_pointer = 0) :

    pointer(_pointer) {}! ! operator tiff *() const { return pointer; }! ! ~TiffWrapper() {! if (pointer)! ! TIFFClose(pointer);! }! ! private:! struct tiff *pointer;! };! Обёртка вокруг struct tiff
  22. class TiffImage {! public:! TiffImage(const QString &fileName = QString::null);! !

    quint32 width() const { return _width; }! quint32 height() const { return _height; }! ! // Загружено ли изображение! operator bool() const { return tif; }! ! typedef quint16 PixelData;! ! // Указатель на данные пиксела (x, y)! const PixelData *pixelPtr(int x, int y);! PixelData pixel(int x, int y) { return *pixelPtr(x, y); }! ! // Сдвинуть вперед на одну строку (y + 1)! const PixelData *nextScanline(const PixelData *ptr);! ! // Сдвинуть назад на одну строку (y - 1)! const PixelData *prevScanline(const PixelData *ptr);! ! // Данные изображения. Данные лениво загружаются при первом обращении! const QByteArray &imageData();! private:! void loadImage();! ! QSharedPointer<TiffWrapper> tif;! QByteArray _imageData;! quint32 _width, _height, _rowsperstrip;! size_t scanlineSize;! bool loaded;! };
  23. • Можно начать с оборачивания базовой структуры данных (Smart pointer

    или как-то ещё). • Часто не нужно оборачивать всё, достаточно сделать красивый ОО-фасад. • Правильную структуру классов нужно брать из головы, в C никакой структуры, как правило, нет. • Исключения для обработки ошибок тоже реализуются на своё усмотрение (в C их нет).