Читаем Thinking In C++. Volume 2: Practical Programming полностью

  zy.b(); // Doesn't create Z::a()

} ///:~

Here, even though the template Z purports to use both f( ) and g( ) member functions of T, the fact that the program compiles shows you that it only generates Z::a( ) when it is explicitly called for zx. (If Z::b( ) were also generated at the same time, a compile-time error message would be generated, because it would attempt to call X::g( ), which doesn’t exist.) Similarly, the call to zy.b( ) doesn’t generate Z::a( ). As a result, the Z template can be used with X and Y; whereas if all the member functions were generated when the class was first created the use of many templates would significantly limited.

Suppose you have a container, a Stack say, and you use specializations for int, int*, and char*. Three versions of Stack code will be generated and linked as part of your program. One of the reasons for using a template in the first place is so you don’t have to replicate code by hand; but code still gets replicated—it’s just the compiler that does it instead of you. You can factor the bulk of the implementation for storing pointer types into a single class by using a combination of full and partial specialization. The key is to fully specialize for void* and then derive all other pointer types from the void* implementation so the common code can be shared. The program below illustrates this technique.

//: C05:Nobloat.h

// Shares code for storing pointers in a Stack

#ifndef NOBLOAT_H

#define NOBLOAT_H

#include

#include

#include

// The primary template

template

class Stack {

  T* data;

  std::size_t count;

  std::size_t capacity;

  enum {INIT = 5};

public:

  Stack() {

    count = 0;

    capacity = INIT;

    data = new T[INIT];

  }

  void push(const T& t) {

    if (count == capacity) {

      // Grow array store

      std::size_t newCapacity = 2*capacity;

      T* newData = new T[newCapacity];

      for (size_t i = 0; i < count; ++i)

        newData[i] = data[i];

      delete [] data;

      data = newData;

      capacity = newCapacity;

    }

    assert(count < capacity);

    data[count++] = t;

  }

  void pop() {

    assert(count > 0);

    --count;

  }

  T top() const {

    assert(count > 0);

    return data[count-1];

  }

  size_t size() const {return count;}

};

// Full specialization for void*

template<>

class Stack {

  void** data;

  std::size_t count;

  std::size_t capacity;

  enum {INIT = 5};

public:

  Stack() {

    count = 0;

    capacity = INIT;

    data = new void*[INIT];

  }

  void push(void* const & t) {

    if (count == capacity) {

      std::size_t newCapacity = 2*capacity;

      void** newData = new void*[newCapacity];

      std::memcpy(newData, data, count*sizeof(void*));

      delete [] data;

      data = newData;

      capacity = newCapacity;

    }

    assert(count < capacity);

    data[count++] = t;

  }

  void pop() {

    assert(count > 0);

    --count;

  }

  void* top() const {

    assert(count > 0);

    return data[count-1];

  }

  std::size_t size() const {return count;}

};

// Partial specialization for other pointer types

template

class Stack : private Stack {

  typedef Stack Base;

public:

  void push(T* const & t) {Base::push(t);}

  void pop() {Base::pop();}

  T* top() const {return static_cast(Base::top());}

  std::size_t size() {return Base::size();}

};

#endif // NOBLOAT_H ///:~.

This simple stack expands as it fills its capacity. The void* specialization stands out as a full specialization by virtue of the template<> prefix (that is, the template parameter list is empty). As mentioned earlier, it is necessary to implement all member functions in a class template specialization. The savings occurs with all other pointer types. The partial specialization for other pointer types derives from Stack privately, since we are merely using Stack for implementation purposes, and do not wish to expose any of its interface directly to the user. The member functions for each pointer instantiation are small forwarding functions to the corresponding functions in Stack. Hence, whenever a pointer type other than void* is instantiated, it is a fraction of the size it would have been had the primary template alone been used.[59] Here is a driver program:.

//: C05:NobloatTest.cpp

#include

#include

#include "Nobloat.h"

using namespace std;

template

void emptyTheStack(StackType& stk) {

  while (stk.size() > 0) {

    cout << stk.top() << endl;

    stk.pop();

  }

}

// An overload for emptyTheStack (not a specialization!)

template

void emptyTheStack(Stack& stk) {

  while (stk.size() > 0) {

    cout << *stk.top() << endl;

    stk.pop();

  }

}

int main() {

  Stack s1;

  s1.push(1);

  s1.push(2);

  emptyTheStack(s1);

  Stack s2;

  int i = 3;

  int j = 4;

  s2.push(&i);

  s2.push(&j);

  emptyTheStack(s2);

} ///:~

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных