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

Sometimes you’d like to create your own manipulators, and it turns out to be remarkably simple. A zero-argument manipulator such as endl is simply a function that takes as its argument an ostream reference and returns an ostream reference. The declaration for endl is.

ostream& endl(ostream&);

Now, when you say:.

cout << "howdy" << endl;

the endl produces the address of that function. So the compiler asks, "Is there a function I can call that takes the address of a function as its argument?" Predefined functions in do this; they’re called applicators (because they apply a function to a stream). The applicator calls its function argument, passing it the ostream object as its argument. You don’t need to know how applicators work to create your own manipulator; you only need to know that they exist. Nonetheless, they’re simple. Here’s the (simplified) code for an ostream applicator:

ostream& ostream::operator<<(ostream& (*pf)(ostream&)) {

  return pf(*this);

}

The actual definition is a little more complicated since it involves templates, but this code illustrates the technique. When a function such as *pf (that takes a stream parameter and returns a stream reference) is inserted into a stream, this applicator function is called, which in turn executes the function to which pf points. Applicators for ios_base, basic_ios, basic_ostream, and basic_istream are predefined in the standard C++ library.

To illustrate the process, here’s a trivial example that creates a manipulator called nl that is equivalent to just inserting a newline into a stream (i.e., no flushing of the stream occurs, as with endl):.

//: C04:nl.cpp

// Creating a manipulator

#include

using namespace std;

ostream& nl(ostream& os) {

  return os << '\n';

}

int main() {

  cout << "newlines" << nl << "between" << nl

       << "each" << nl << "word" << nl;

} ///:~

When you insert nl into an output stream, such as cout, the following sequence of calls ensues:

cout.operator<<(nl) è nl(cout)

The expression

os << '\n';

inside nl( ) calls ostream::operator(char), which of course returns the stream, which is what is ultimately returned from nl( ).[45] 

<p>Effectors</p>

As you’ve seen, zero-argument manipulators are easy to create. But what if you want to create a manipulator that takes arguments? If you inspect the header, you’ll see a type called smanip, which is what the manipulators with arguments return. You might be tempted to somehow use that type to define your own manipulators, but don’t give in to the temptation. The smanip type is implementation-dependent, so using it would not be portable. Fortunately, you can define such manipulators in a straightforward way without any special machinery, based on a technique introduced by Jerry Schwarz, called an effector.[46] An effector is a simple class whose constructor formats a string representing the desired operation, along with an overloaded operator<< to insert that string into a stream. Here’s an example with two effectors. The first outputs a truncated character string, and the second prints a number in binary.

//: C04:Effector.cpp

// Jerry Schwarz's "effectors"

#include

#include   // For max()

#include

#include

using namespace std;

// Put out a prefix of a string:

class Fixw {

  string str;

public:

  Fixw(const string& s, int width)

    : str(s, 0, width) {}

  friend ostream&

  operator<<(ostream& os, const Fixw& fw) {

    return os << fw.str;

  }

};

// Print a number in binary:

typedef unsigned long ulong;

class Bin {

  ulong n;

public:

  Bin(ulong nn) { n = nn; }

  friend ostream& operator<<(ostream& os, const Bin& b) {

    const ulong ULMAX = numeric_limits::max();

    ulong bit = ~(ULMAX >> 1); // Top bit set

    while(bit) {

      os << (b.n & bit ? '1' : '0');

      bit >>= 1;

    }

    return os;

  }

};

int main() {

  string words =

    "Things that make us happy, make us wise";

  for(int i = words.size(); --i >= 0;) {

    ostringstream s;

    s << Fixw(words, i);

    assert(s.str() == words.substr(0, i));

  }

  ostringstream xs, ys;

  xs << Bin(0xCAFEBABEUL);

  assert(xs.str() ==

    "1100""1010""1111""1110""1011""1010""1011""1110");

  ys << Bin(0x76543210UL);

  assert(ys.str() ==

    "0111""0110""0101""0100""0011""0010""0001""0000");

} ///:~

The constructor for Fixw creates a shortened copy of its char* argument, and the destructor releases the memory created for this copy. The overloaded operator<< takes the contents of its second argument, the Fixw object, inserts it into the first argument, the ostream, and then returns the ostream so that it can be used in a chained expression. When you use Fixw in an expression like this:.

cout << Fixw(string, i) << endl;

a temporary object is created by the call to the Fixw constructor, and that temporary object is passed to operator<<. The effect is that of a manipulator with arguments. The temporary Fixw object persists until the end of the statement.

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

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

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

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

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

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

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

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

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