2009-06-15 54 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