2009-06-15 66 views
31

什麼是C++中的代理類?爲什麼它被創建並在哪裏有用?C++中的代理類是什麼

+1

代理(很多其他含義中)是一個**設計模式** - 參見[維基百科](http://en.wikipedia.org/wiki/Proxy_pattern)獲得優秀的覆蓋率(當然,不是強烈的C++特定)。 – 2009-06-15 04:32:00

+0

完全同意,這裏提供了對這個問題的出色答案 – vsoftco 2014-10-31 00:42:40

回答

58

代理是一個爲另一個類提供修改接口的類。下面是一個例子 - 假設我們有我們只希望能夠包含二進制數字1或0.這是第一次嘗試一個數組類:

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

我們希望運營商[]抱怨,如果我們說類似於[1] = 42,但這是不可能的,因爲操作符只能看到數組中的索引,而不是存儲的值。

我們可以解決這個使用代理:

#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; 
    } 
} 

代理類現在做我們的檢查對二進制數字,我們使數組的操作符[]返回具有有限的訪問代理的實例數組的內部。

2

A 代理類允許你隱藏從類的客戶端的類的私人數據。

爲您的課程的客戶提供僅知道您的課程的公共接口的代理類,使客戶能夠使用您班級的服務,而無需讓客戶端訪問您班級的實施細節。

8

C++中的代理類用於實現Proxy Pattern,其中對象是某個其他對象的接口或中介。

C++中代理類的典型用法是實現[]運算符,因爲[]運算符可用於獲取數據或設置對象中的數據。其思想是提供一個代理類,它允許檢測[]運算符的獲取數據使用情況與[]運算符的設置數據使用情況。類的[]運算符使用代理對象通過檢測是否正在使用[]運算符來獲取或設置對象中的數據來協助做正確的事情。

C++編譯器從提供的目標類和代理類定義中選擇合適的運算符和轉換運算符,以便特別使用[]運算符工作。

但是在C++中還有其他用途。例如,請參閱Dobbs博士的Self-Registering Objects in C++上的這篇文章,其中描述了使用代理類作爲對象工廠的一部分。對象工廠根據一些標準提供特定類型的對象,在本例中爲圖形圖像格式。每個不同的圖形圖像轉換器都由代理對象表示。

所有這些要求可以通過使用「專賣店」,在 其中有在一個知道 所有支持格式編譯時的代碼沒有任何一個地方得到滿足。當每個文件格式對象註冊一個 專用存儲對象時,支持的對象列表的內建值爲 運行時間。

有四個部分,以建立一個專賣店:

  • 每一類去店裏將通過代理類來表示。該代理知道如何爲商店創建對象,併爲關於該類的信息提供標準接口。
  • 您必須決定專業商店將向調用者公開什麼標準,然後在商店中實現這些標準的接口, 代理類以及原始類中的接口。
  • 所有代理類都將從一個公共基類派生,以便專業商店可以互換使用它們。每個代理類將爲 ,作爲調用原始 類中的靜態函數的模板實現。
  • 代理類將在程序啓動時自動註冊,方法是爲每個代理類定義一個全局變量,其構造函數 將向專業商店註冊代理類。

另一個例子是微軟DCOM(分佈式COM)對象如何使用代理的DCOM對象的用戶的主機上表示它位於另一主機上的實際的對象。代理爲不同機器上的實際對象提供接口,並處理對象用戶與實際對象之間的通信。

總之,代理對象用作實際對象的中介。當需要在對象的用戶和具有某種間接方向的實際對象之間進行某種類型的轉換或轉換時,使用代理對象,該對象在使用中存在某些障礙時提供允許使用實際對象的服務直接的實際對象。

編輯 - 使用具有運算符[]代理的簡單陣列數據存儲

下面的源一個簡單的例子使用代理對象一類的操作員[]。下面提供了測試工具的輸出,以顯示各種代理對象的創建和銷燬,因爲代理類用於訪問和操作實際的類。在調試器中運行它來觀察它的執行是有益的。

// 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