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

Now we encounter a dilemma. Objects that are being observed may have more than one such item of interest. For example, if you’re dealing with a GUI item—a button, say—the items of interest might be the mouse clicked the button, the mouse moved over the button, and (for some reason) the button changed its color. So we’d like to be able to report all these events to different observers, each of which is interested in a different type of event.

The problem is that we would normally reach for multiple inheritance in such a situation: "I’ll inherit from Observable to deal with mouse clicks, and I’ll … er … inherit from Observable to deal with mouse-overs, and, well, … hmm, that doesn’t work."

<p>The "inner class" idiom</p>

Here’s a situation in which we do actually need to (in effect) upcast to more than one type, but in this case we need to provide several different implementations of the same base type. The solution is something we’ve lifted from Java, which takes C++’s nested class one step further. Java has a built-in feature called an inner class, which is like a nested class in C++, but it has access to the nonstatic data of its containing class by implicitly using the "this" pointer of the class object it was created within.[124] 

To implement the inner class idiom in C++, we must obtain and use a pointer to the containing object explicitly. Here’s an example:

//: C10:InnerClassIdiom.cpp

// Example of the "inner class" idiom

#include

#include

using namespace std;

class Poingable {

public:

  virtual void poing() = 0;

};

void callPoing(Poingable& p) {

  p.poing();

}

class Bingable {

public:

  virtual void bing() = 0;

};

void callBing(Bingable& b) {

  b.bing();

}

class Outer {

  string name;

  // Define one inner class:

  class Inner1;

  friend class Outer::Inner1;

  class Inner1 : public Poingable {

    Outer* parent;

  public:

    Inner1(Outer* p) : parent(p) {}

    void poing() {

      cout << "poing called for "

        << parent->name << endl;

      // Accesses data in the outer class object

    }

  } inner1;

  // Define a second inner class:

  class Inner2;

  friend class Outer::Inner2;

  class Inner2 : public Bingable {

    Outer* parent;

  public:

    Inner2(Outer* p) : parent(p) {}

    void bing() {

      cout << "bing called for "

        << parent->name << endl;

    }

  } inner2;

public:

  Outer(const string& nm) : name(nm),

    inner1(this), inner2(this) {}

  // Return reference to interfaces

  //  implemented by the inner classes:

  operator Poingable&() { return inner1; }

  operator Bingable&() { return inner2; }

};

int main() {

  Outer x("Ping Pong");

  // Like upcasting to multiple base types!:

  callPoing(x);

  callBing(x);

} ///:~

The example begins with the Poingable and Bingable interfaces, each of which contain a single member function. The services provided by callPoing( ) and callBing( ) require that the object they receive implement the Poingable and Bingable interfaces, respectively, but they put no other requirements on that object so as to maximize the flexibility of using callPoing( ) and callBing( ). Note the lack of virtual destructors in either interface—the intent is that you never perform object destruction via the interface.

The Outer constructor contains some private data (name), and it wants to provide both a Poingable interface and a Bingable interface so it can be used with callPoing( ) and callBing( ). Of course, in this situation we could simply use multiple inheritance. This example is just intended to show the simplest syntax for the idiom; you’ll see a real use shortly. To provide a Poingable object without deriving Outer from Poingable, the inner class idiom is used. First, the declaration class Inner says that, somewhere, there is a nested class of this name. This allows the friend declaration for the class, which follows. Finally, now that the nested class has been granted access to all the private elements of Outer, the class can be defined. Notice that it keeps a pointer to the Outer which created it, and this pointer must be initialized in the constructor. Finally, the poing( ) function from Poingable is implemented. The same process occurs for the second inner class which implements Bingable. Each inner class has a single private instance created, which is initialized in the Outer constructor. By creating the member objects and returning references to them, issues of object lifetime are eliminated.

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

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

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

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

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

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

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

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

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