Подтвердить что ты не робот

Что такое прокси-класс в С++

Что такое прокси-класс в С++? Почему он создан и где он полезен?

4b9b3361

Ответ 1

Прокси - это класс, который предоставляет модифицированный интерфейс другому классу.

Вот пример - предположим, у нас есть класс массива, который мы хотим содержать только двоичные цифры (1 или 0). Вот первая попытка:

struct array1 {
    int mArray[10];
    int & operator[](int i) {
      /// what to put here
    }
}; '

Мы хотим, чтобы operator[] выдавал, если мы говорим что-то вроде a[1] = 42, но это невозможно, потому что этот оператор видит только индекс массива, а не сохраняемое значение.

Мы можем решить это с помощью прокси:

#include <iostream>
using namespace std;

struct aproxy {
    aproxy(int& r) : mPtr(&r) {}
    void operator = (int n) {
        if (n > 1 || n < 0) {
            throw "not binary digit";
        }
        *mPtr = n;
    }
    int * mPtr;
};

struct array {
    int mArray[10];
    aproxy operator[](int i) {
        return aproxy(mArray[i]);
    }
};

int main() {
    try {
        array a;
        a[0] = 1;   // ok
        a[0] = 42;  // throws exception
    }
    catch (const char * e) {
        cout << e << endl;
    }
}

Теперь прокси-класс проверяет двоичную цифру, и мы заставляем operator[] массива operator[] возвращать экземпляр прокси, который имеет ограниченный доступ к внутренним объектам массива.

Ответ 2

Прокси-класс в C++ используется для реализации шаблона прокси, в котором объект является интерфейсом или посредником для какого-либо другого объекта.

Типичное использование прокси-класса в C++ реализует оператор [], поскольку оператор [] может использоваться для получения данных или для установки данных внутри объекта. Идея состоит в том, чтобы предоставить прокси-класс, который позволяет обнаруживать использование данных для использования данных с помощью оператора [] по сравнению с использованием заданного использования оператора []. Оператор [] класса использует прокси-объект, чтобы помочь сделать правильную вещь, обнаружив, используется ли оператор [] для получения или установки данных в объекте.

Компилятор C++ выбирает соответствующие операторы и операторы преобразования из предоставленного целевого класса и определения класса прокси, чтобы использовать конкретную работу оператора [].

Однако для прокси-класса в C++ существуют другие применения. Например, см. Эту статью о саморегистрации объектов в C++ от доктора Доббса, которая описывает использование прокси-класса как части фабрики объектов. Объектная фабрика предоставляет определенный тип объекта в зависимости от некоторых критериев, в этом примере - формат графического изображения. Каждый из различных графических преобразователей изображения представлен прокси-объектом.

Все эти требования могут быть выполнены с помощью "специализированного магазина", в котором во время компиляции нет единого места в коде, которое знает обо всех поддерживаемых форматах. Список поддерживаемых объектов создается во время выполнения, когда каждый объект формата файла регистрирует свое существование со специальным хранилищем.

Существует четыре части для создания специализированного магазина:

  • Каждый класс, который идет в магазине, будет представлен прокси-классом. Прокси знает, как создавать объекты для хранилища и предоставляет стандартный интерфейс для информации о классе.
  • Вы должны решить, какие критерии специализированное хранилище будет раскрыто для вызывающих, затем реализовать интерфейсы для этих критериев в хранилище, в прокси-классе и в исходном классе.
  • Все классы-прокси будут получены из общего базового класса, чтобы специализированный магазин мог использовать их взаимозаменяемо. Каждый класс прокси будет реализован как шаблон, который вызывает статические функции в исходном классе.
  • Прокси-классы будут автоматически регистрироваться при запуске программы, определяя глобальную переменную для каждого прокси-класса, конструктор которого зарегистрирует прокси-класс в специализированном хранилище.

См. Также этот ответ fooobar.com/questions/29848/... на вопрос об итераторах C++, в которых прокси-класс используется для представления в качестве уникального объекта каждого из элементов массива структуры. Структура представляет собой резидентную базу данных для встроенного приложения. Несколько различных видов мнемоники хранятся в виде массивов текстовых символов в резидентной базе данных. Класс proxy предоставляет представление, которое затем может использоваться с итератором для перемещения списка мнемоник в определенной области. Итератор обращается к прокси-объекту через базовый класс и интеллект относительно того, сколько мнемоников представляет объект-прокси, и длина каждой мнемоники находится в самом прокси-объекте.

Другим примером может быть то, как объекты Microsoft DCOM (Distributed COM) используют прокси-сервер на главной машине пользователя объекта DCOM для представления фактического объекта, который находится на другом хост-компьютере. Прокси обеспечивает интерфейс для фактического объекта на другой машине и обрабатывает связь между пользователем объекта и фактическим объектом.

Подводя итог, прокси-объект используется для того, чтобы выступать в качестве посредника к фактическому объекту. Прокси-объект используется, когда когда-либо должно быть какое-то преобразование или преобразование между пользователем объекта и фактическим объектом с каким-либо косвенным режимом, который предоставляет услугу, позволяющую использовать фактический объект, когда есть какое-то препятствие при использовании фактический объект напрямую.

EDIT - простой пример использования прокси с оператором [] для простого хранилища данных массива

Следующий источник использует прокси-объект для оператора [] класса. Результат тестового жгута приведен ниже, чтобы показать создание и уничтожение различных прокси-объектов, поскольку прокси-класс используется для доступа к фактическому классу и управления им. Поучительно запускать это в отладчике, чтобы наблюдать за его выполнением.

// proxy.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string.h>

#include <iostream>

class TArrayProxy;

// The actual class which we will access using a proxy.
class TArray
{
public:
    TArray();
    ~TArray ();

    TArrayProxy operator [] (int iIndex);
    int operator = (TArrayProxy &j);
    void Dump (void);

    char    m_TarrayName[4];     // this is the unique name of a particular object.

    static char TarrayName[4];   // This is the global used to create unique object names

private:
    friend class TArrayProxy;    // allow the proxy class access to our data.
    int iArray[10];              // a simple integer array for our data store
};

// The proxy class which is used to access the actual class.
class TArrayProxy
{
public:
    TArrayProxy(TArray *p = 0, int i=0);
    ~TArrayProxy();

    TArrayProxy & operator = (int i);
    TArrayProxy & operator += (int i);
    TArrayProxy & operator = (TArrayProxy &src);
    operator int ();

    int     iIndex;
    char    m_TarrayproxyName[4];        // this is the unique name of a particular object.

    static char TarrayproxyName[4];      // This is the global used to create unique object names

private:
    TArray *pArray;                      // pointer to the actual object for which we are a proxy.
};

// initialize the object names so as to generate unique object names.
char TArray::TarrayName[4] = {" AA"};
char TArrayProxy::TarrayproxyName[4] = {" PA"};

// Construct a proxy object for the actual object along with which particular
// element of the actual object data store that this proxy will represent.
TArrayProxy::TArrayProxy(TArray *p /* = 0 */, int i /* = 0 */)
{
    if (p && i > 0) {
        pArray = p;
        iIndex = i;
        strcpy (m_TarrayproxyName, TarrayproxyName);
        TarrayproxyName[2]++;
        std::cout << "    Create TArrayProxy " << m_TarrayproxyName << " iIndex = " << iIndex  << std::endl;
    } else {
        throw "TArrayProxy bad p";
    }
}

// The destructor is here just so that we can log when it is hit.
TArrayProxy::~TArrayProxy()
{
    std::cout << "      Destroy TArrayProxy " << m_TarrayproxyName << std::endl;
}

// assign an integer value to a data store element by using the proxy object
// for the particular element of the data store.
TArrayProxy & TArrayProxy::operator = (int i)
{
    pArray->iArray[iIndex] = i;
    std::cout << "      TArrayProxy assign = i " << i << " to " << pArray->m_TarrayName << " using proxy " << m_TarrayproxyName << " iIndex " << iIndex << std::endl;
    return *this;
}

TArrayProxy & TArrayProxy::operator += (int i)
{
    pArray->iArray[iIndex] += i;
    std::cout << "      TArrayProxy add assign += i " << i << " to " << pArray->m_TarrayName << " using proxy " << m_TarrayproxyName << " iIndex " << iIndex << std::endl;
    return *this;
}

// assign an integer value that is specified by a proxy object to a proxy object for a different element.
TArrayProxy & TArrayProxy::operator = (TArrayProxy &src)
{
    pArray->iArray[iIndex] = src.pArray->iArray[src.iIndex];
    std::cout << "      TArrayProxy assign = src " << src.m_TarrayproxyName << " iIndex " << src.iIndex << " to " << m_TarrayproxyName << " iIndex "<< iIndex << " from"  << std::endl;
    return *this;
}

TArrayProxy::operator int ()
{
    std::cout << "      TArrayProxy operator int " << m_TarrayproxyName << " iIndex " << iIndex << " value of " << pArray->iArray[iIndex] << std::endl;
    return pArray->iArray[iIndex];
}



TArray::TArray()
{
    strcpy (m_TarrayName, TarrayName);
    TarrayName[2]++;
    std::cout << "  Create TArray = " << m_TarrayName << std::endl;
    for (int i = 0; i < sizeof(iArray)/sizeof(iArray[0]); i++) { iArray[i] = i; }
}

// The destructor is here just so that we can log when it is hit.
TArray::~TArray()
{
    std::cout << "  Destroy TArray " << m_TarrayName << std::endl;
}

TArrayProxy TArray::operator [] (int iIndex)
{
    std::cout << "  TArray operator [" << iIndex << "] " << m_TarrayName << std::endl;
    if (iIndex > 0 && iIndex <= sizeof(iArray)/sizeof(iArray[0])) {
        // create a proxy object for this particular data store element
        return TArrayProxy(this, iIndex);
    }
    else
        throw "Out of range";
}

int TArray::operator = (TArrayProxy &j)
{
    std::cout << "  TArray operator = " << m_TarrayName << " from" << j.m_TarrayproxyName << " index " << j.iIndex << std::endl;
    return j.iIndex;
}

void TArray::Dump (void)
{
    std::cout << std::endl << "Dump of " << m_TarrayName << std::endl;
    for (int i = 0; i < sizeof(iArray)/sizeof(iArray[0]); i++) {
        std::cout << "  i = " << i << "  value = " << iArray [i] << std::endl;
    }
}

// -----------------    Main test harness follows  ----------------
// we will output the line of code being hit followed by the log of object actions.

int _tmain(int argc, _TCHAR* argv[])
{
    TArray myObj;

    std::cout << std::endl  << "int ik = myObj[3];" << std::endl;
    int ik = myObj[3];
    std::cout << std::endl << "myObj[6] = myObj[4] = 40;" << std::endl;
    myObj[6] = myObj[4] = 40;
    std::cout << std::endl << "myObj[5] = myObj[5];" << std::endl;
    myObj[5] = myObj[5];
    std::cout << std::endl << "myObj[2] = 32;" << std::endl;
    myObj[2] = 32;
    std::cout << std::endl << "myObj[8] += 20;" << std::endl;
    myObj[8] += 20;
    myObj.Dump ();
    return 0;
}

И вот вывод этого примера из консольного приложения с Visual Studio 2005.

  Create TArray =  AA

int ik = myObj[3];
  TArray operator [3]  AA
    Create TArrayProxy  PA iIndex = 3
      TArrayProxy operator int  PA iIndex 3 value of 3
      Destroy TArrayProxy  PA

myObj[6] = myObj[4] = 40;
  TArray operator [4]  AA
    Create TArrayProxy  PB iIndex = 4
      TArrayProxy assign = i 40 to  AA using proxy  PB iIndex 4
  TArray operator [6]  AA
    Create TArrayProxy  PC iIndex = 6
      TArrayProxy assign = src  PB iIndex 4 to  PC iIndex 6 from
      Destroy TArrayProxy  PC
      Destroy TArrayProxy  PB

myObj[5] = myObj[5];
  TArray operator [5]  AA
    Create TArrayProxy  PD iIndex = 5
      TArrayProxy operator int  PD iIndex 5 value of 5
  TArray operator [5]  AA
    Create TArrayProxy  PE iIndex = 5
      TArrayProxy assign = i 5 to  AA using proxy  PE iIndex 5
      Destroy TArrayProxy  PE
      Destroy TArrayProxy  PD

myObj[2] = 32;
  TArray operator [2]  AA
    Create TArrayProxy  PF iIndex = 2
      TArrayProxy assign = i 32 to  AA using proxy  PF iIndex 2
      Destroy TArrayProxy  PF

myObj[8] += 20;
  TArray operator [8]  AA
    Create TArrayProxy  PG iIndex = 8
      TArrayProxy add assign += i 20 to  AA using proxy  PG iIndex 8
      Destroy TArrayProxy  PG

Dump of  AA
  i = 0  value = 0
  i = 1  value = 1
  i = 2  value = 32
  i = 3  value = 3
  i = 4  value = 40
  i = 5  value = 5
  i = 6  value = 40
  i = 7  value = 7
  i = 8  value = 28
  i = 9  value = 9

Ответ 3

A прокси-класс позволяет скрывать личные данные класса от клиентов класса.

Предоставление клиентам вашего класса прокси-класса, который знает только открытый интерфейс вашего класса, позволяет клиентам использовать ваши сервисы класса, не предоставляя клиенту доступ к вашим сведениям о реализации класса.