C++のプロキシクラスとは何ですか?なぜ作成され、どこで役立つのですか?
プロキシは、別のクラスへの変更されたインターフェイスを提供するクラスです。
以下に例を示します-バイナリクラス(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;
}
}
プロキシクラスは現在、2進数のチェックを行い、配列のoperator[]
は、配列の内部へのアクセスが制限されているプロキシのインスタンスを返します。
C++のプロキシクラスは、オブジェクトが他のオブジェクトのインターフェイスまたはメディエーターである Proxy Pattern を実装するために使用されます。
C++でのプロキシクラスの一般的な使用方法は、[]演算子を実装することです。これは、[]演算子を使用してデータを取得したり、オブジェクト内のデータを設定したりできるためです。その考え方は、[]演算子のデータ取得の使用と[]演算子の設定データの使用の検出を可能にするプロキシクラスを提供することです。クラスの[]演算子は、プロキシオブジェクトを使用して、オブジェクト内のデータを取得または設定するために[]演算子が使用されているかどうかを検出することにより、正しいことを支援します。
C++コンパイラは、[]演算子の特定の使用を機能させるために、提供されたターゲットクラスとプロキシクラス定義から適切な演算子と変換演算子を選択します。
ただし、C++のプロキシクラスには他の用途があります。たとえば、オブジェクトファクトリの一部としてプロキシクラスを使用する方法について説明しているドブス博士の C++での自己登録オブジェクト に関するこの記事を参照してください。オブジェクトファクトリは、いくつかの基準に応じて特定の種類のオブジェクトを提供します。この例では、グラフィックイメージ形式です。異なるグラフィックイメージコンバーターのそれぞれは、プロキシオブジェクトによって表されます。
これらの要件はすべて、「専門店」を使用することで満たすことができます。「専門店」では、コンパイル時に、サポートされているすべての形式を知っているコード内の単一の場所はありません。サポートされるオブジェクトのリストは、各ファイル形式オブジェクトがその存在を専門店オブジェクトに登録するときに実行時に作成されます。
専門店を構築するには、4つの部分があります。
- ストアに入る各クラスは、プロキシクラスによって表されます。プロキシは、ストアのオブジェクトを作成する方法を認識しており、クラスに関する情報の標準インターフェイスを提供します。
- 専門店が呼び出し元に公開する基準を決定し、ストア、プロキシクラス、および元のクラスでそれらの基準のインターフェイスを実装する必要があります。
- すべてのプロキシクラスは、共通の基本クラスから派生するため、専門店はそれらを互換的に使用できます。各プロキシクラスは、元のクラスの静的関数を呼び出すテンプレートとして実装されます。
- プロキシクラスは、コンストラクタがプロキシストアを専門店に登録するプロキシクラスごとにグローバル変数を定義することにより、プログラムの起動時に自動的に登録されます。
プロキシクラスを使用して各配列メンバーを一意のオブジェクトとして表すC++イテレーターに関する質問については、この回答 https://stackoverflow.com/a/53253728/146697 も参照してください。構造体の。構造体は、組み込みアプリケーション用のメモリ常駐データベースです。いくつかの異なる種類のニーモニックが、メモリ常駐データベースにテキスト文字配列として保存されます。プロキシクラスは、特定の領域でニーモニックのリストを走査するために反復子で使用できる表現を提供します。イテレータは、基本クラスと、プロキシオブジェクトが表すニーモニックの数と、各ニーモニックの長さがプロキシオブジェクト自体にあるかどうかに関するインテリジェンスを通じて、プロキシオブジェクトにアクセスします。
別の例は、Microsoft DCOM(分散COM)オブジェクトがDCOMオブジェクトのユーザーのホストマシン上のプロキシを使用して、別のホストマシンに存在する実際のオブジェクトを表す方法です。プロキシは、異なるマシン上の実際のオブジェクトにインターフェースを提供し、オブジェクトのユーザーと実際のオブジェクト間の通信を処理します。
要約すると、プロキシオブジェクトを使用して、実際のオブジェクトの仲介として機能します。プロキシオブジェクトは、オブジェクトのユーザーと実際のオブジェクトとの間に何らかの変換または変換が必要な場合に使用されます。実際のオブジェクト。
EDIT-単純な配列データストアに演算子[]を使用したプロキシを使用した簡単な例
次のソースは、クラスのoperator []にプロキシオブジェクトを使用しています。テストハーネスの出力は、実際のクラスへのアクセスと操作にプロキシクラスが使用されるため、さまざまなプロキシオブジェクトの作成と破棄を示すために以下に提供されています。これをデバッガで実行して実行を監視することは有益です。
// 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
プロキシクラスを使用すると、クラスのクライアントからクラスのプライベートデータをhideできます。
クラスのクライアントにクラスへのパブリックインターフェイスのみを知っているプロキシクラスを提供すると、クライアントは、クラスの実装の詳細へのアクセスをクライアントに与えることなく、クラスのサービスを使用できます。