Qu'est-ce que la classe Proxy en C++?
Qu'est-ce qu'une classe Proxy en C++? Pourquoi il est créé et où il est utile?
3 réponses
un proxy est une classe qui fournit une interface modifiée à une autre classe. Voici un exemple-supposons que nous ayons une classe de tableaux que nous voulons seulement pouvoir contenir les chiffres binaires 1 ou 0. Voici un premier essai:
struct array1 {
int mArray[10];
int & operator[](int i) {
/// what to put here
}
}; `
nous voulons que l'opérateur [] se plaint si nous disons quelque chose comme un[1] = 42, mais ce n'est pas possible parce que l'opérateur ne voit que l'index de dans le tableau, pas la valeur étant stockée.
nous pouvons résoudre cela en utilisant un proxy:
#include <iostream>
using namespace std;
struct aproxy {
aproxy(int& r) : mPtr(&r) {}
void operator = (int n) {
if (n > 1) {
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;
}
}
la classe proxy fait maintenant notre vérification d'un chiffre binaire et nous faisons l'opérateur du tableau[] retourner une instance du proxy qui a un accès limité aux internes du tableau.
une classe proxy en C++ est utilisée pour implémenter le Motif De Procuration dans laquelle un objet est une interface ou d'un médiateur pour un autre objet.
une utilisation typique d'une classe proxy en c++ est l'implémentation de l'opérateur [] puisque l'opérateur [] peut être utilisé pour obtenir des données ou pour définir des données à l'intérieur d'un objet. L'idée est de fournir une classe de proxy qui permet la détection d'une utilisation des données de l'opérateur [] rapport à l'ensemble des données de l'utilisation de l'opérateur []. L'opérateur [] d'un la classe utilise l'objet proxy pour aider à faire la bonne chose en détectant si l'opérateur [] est utilisé pour obtenir ou définir les données de l'objet.
le compilateur C++ sélectionne les opérateurs et les opérateurs de conversion appropriés à partir de la classe cible fournie et des définitions de la classe proxy afin de faire fonctionner une utilisation particulière de l'opérateur [].
cependant il y a d'autres utilisations pour une classe proxy en C++. Par exemple, voir cet article sur Auto-Inscription Les objets en C++ du Dr Dobbs qui décrit l'utilisation d'une classe de proxy comme partie d'une usine d'objets. L'usine d'objet fournit un type particulier d'objet en fonction de certains critères, dans cet exemple un format d'image graphique. Chacun des différents convertisseurs d'image graphique est représenté par un objet proxy.
- Chaque classe qui va dans le magasin sera représenté par une classe proxy. Le mandataire sait comment créer des objets pour le magasin et fournit une interface standard pour les informations sur la classe.
- Vous devez décider ce que les critères que le magasin spécialisé exposera aux appelants, puis mettra en œuvre des interfaces pour ces critères dans le magasin, en la catégorie des procurations, et dans la catégorie initiale.
- toutes les classes proxy dériveront d'une classe de base commune de sorte que le magasin spécialisé puisse les utiliser de façon interchangeable. Chaque catégorie de procurations sera mis en œuvre comme un modèle qui appelle les fonctions statiques dans l'original classe.
- les classes Proxy seront enregistrées automatiquement au démarrage du programme en définissant une variable globale pour chaque classe de proxy dont le constructeur enregistrera la classe proxy dans le magasin spécialisé.
un autre exemple serait comment les objets Microsoft DCOM (Distributed COM) utilisent un proxy sur la machine hôte d'un utilisateur de L'objet DCOM pour représenter l'objet réel qui réside sur une autre machine hôte. Le proxy fournit une interface pour l'objet réel sur une machine différente, et gère la communication entre l'utilisateur de l'objet et l'objet réel.
en résumé, un objet de procuration sert d'intermédiaire entre l'objet réel et l'objet réel. Un objet proxy est utilisé quand jamais il doit y avoir une sorte de conversion ou de transformation entre l'utilisateur d'un objet et l'objet lui-même avec une sorte d'indirection qui fournit un service permettant l'utilisation de l'objet lui-même lorsqu'il existe un obstacle dans l'utilisation de l'objet réel directement.
modifier - un exemple simple utilisant un proxy avec l'opérateur [] pour un tableau simple banque de données
la source suivante utilise un objet proxy pour l'opérateur[] d'une classe. La sortie du harnais d'essai est fournie ci-dessous pour montrer la création et la destruction des divers objets proxy alors que la classe proxy est utilisée pour accéder et manipuler la classe réelle. Il est instructif d'exécuter ce dans un débogueur pour le regarder s'exécuter.
// 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;
}
et voici la sortie de cet exemple à partir D'une application console avec 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
classe proxy permet masquer les données privées d'une classe de clients de la classe.
fournir aux clients de votre classe une classe proxy qui ne connaît que l'interface publique de votre classe permet aux clients d'utiliser les services de votre classe sans donner au client accès aux détails d'implémentation de votre classe.