c++代理類

來源:互聯網
上載者:User

其實代理模式跟這個差不多,對象A(相當於瀏覽器)不是直接存取對象C(相當Web伺服器),而是通過一個中間對象B(相當於Proxy 伺服器)間接訪問對象C。對象B則可以利用這一有利位置為A提供一個與C完全不同的介面,或做一些C本來不做的事!流程如所示:

A -----> B ------> C

這樣B就是C的代理類,C可被稱作實作類別,A是客戶代碼。

==================
下面是原始碼,一共4個檔案。其中實作類別成員函數為全部寫成內嵌函式。
1. 實作類別檔案implementation.h:
// implementation.h --
// 2006-07-21 14:20

#ifndef IMPLEMENTATION_H_
#define IMPLEMENTATION_H_

class Implementation {
public:

Implementation(int v) { value = v; }

void setValue(int v) { value = v; }

int  getValue() const { return value; }

private:

int value;

};
#endif

2. 代理類標頭檔interface.h:
// interface.h -- Interface類是Implementation類的代理類
// 2006-07-21 14:23

#ifndef INTERFACE_H_
#define INTERFACE_H_

class Implementation;  // forward class declaration

class Interface {      // Interface代理類
public:

Interface(int v);

void setValue(int v);

int  getValue() const;

~Interface();

private:

Implementation * ptr;

};

#endif

3. 代理類實現檔案interface.cpp:
// interface.cpp
// 2006-07-21 14:25

#include "implementation.h"
#include "interface.h"

Interface::Interface(int v) : ptr(new Implementation(v)) {
}

void Interface::setValue(int v) {

ptr->setValue(v);

}

int Interface::getValue() const {

return ptr->getValue();

}

Interface::~Interface() {

delete ptr;

}

4. 客戶代碼,這裡只是一個主函數,使用代理模式,檔案:useproxy.cpp:
// useproxy.cpp -- Use proxy class
// 2006-07-21 14:29

#include <iostream>
#include "implementation.h"
#include "interface.h"
using namespace std;

int main() {

Interface i(5);

cout << "Interface contains: " << i.getValue() << " before setValue/n";

i.setValue(10);

cout << "Interface contains: " << i.getValue() << " after setValue/n";

return 0;

}

=======================
運行結果:
Interface contains: 5 before setValue
Interface contains: 10 after setValue
Press any key to continue

=========================
說明:在useproxy.cpp檔案中,只有一個Interface類對象,即代理類對象,所有的操作都是調用代理類的公有函數,間接操作實作類別。

---------------------------------------

// 代理類 Demo// 將繼承和容器共用,迫使我們要處理兩個問題:// 控制記憶體配置和把不同類型的對象放入同一個容器中。// 代理類的每個對象都代表另一個對象,該對象可以是// 位於一個完整繼承層次中的任何類的對象。通過在容器中// 用代理對象而不是對象本身來解決以上兩個問題#include <process.h>        // system()#include <iostream>using namespace std;// 所有交通工具的基類class Vehicle{public:    virtual void start() = 0;    // 動態複製    virtual Vehicle* copy() const = 0;    // 虛解構函式    virtual ~Vehicle() {}};// 交通工具的代理類class VehicleSurrogate{public:    // 無參建構函式,用於建立數組    VehicleSurrogate();    // 用Vehicle 及其衍生類別構造    VehicleSurrogate(const Vehicle&);    ~VehicleSurrogate();    // 拷貝及賦值    VehicleSurrogate(const VehicleSurrogate&);    VehicleSurrogate& operator=(const VehicleSurrogate&);    // Vehicle 的方法    void start();private:    Vehicle* p;};VehicleSurrogate::VehicleSurrogate() : p(0) {}VehicleSurrogate::VehicleSurrogate(const Vehicle& v) : p(v.copy()) {}VehicleSurrogate::VehicleSurrogate(const VehicleSurrogate& vs) : p(vs.p ? vs.p->copy() : 0) {}VehicleSurrogate & VehicleSurrogate::operator =(const VehicleSurrogate& vs){    if (p != vs.p)    {        delete p;        p = vs.p ? vs.p->copy() : 0;    }    return *this;}VehicleSurrogate::~VehicleSurrogate() { delete p; }void VehicleSurrogate::start(){    if (p)        p->start();    else        cout << "Error" << endl;}class RoadVehicle : public Vehicle{public :    void start()    {        cout << "RoadVehicle start." << endl;    }    Vehicle* copy() const    {        return (Vehicle*) new RoadVehicle(*this);    }    ~RoadVehicle()    {    }};class AutoVehicle : public RoadVehicle{public :    void start()    {        cout << "AutoVehicle start." << endl;    }    Vehicle* copy() const    {        return (Vehicle*) new AutoVehicle(*this);    }    ~AutoVehicle()    {    }};void main(){    VehicleSurrogate pa[3];    RoadVehicle* prv = new RoadVehicle();    pa[0] = *prv;    delete prv;    pa[1] = AutoVehicle();    pa[2] = RoadVehicle();    pa[0].start();    pa[1].start();    pa[2].start();    system("pause");}

---------------------------------

問題:怎樣設計一個c++容器,使它有能力包含類型不同而彼此相關的對象?

假設有一個表示不同種類的交通工具的類派生層次:

class Vehicle

{

public:

virtual double weight() const = 0;

virtual void start() = 0;

//.....

};

class RoadVehicle:public Vehicle {/*...*/};

class AutoVehicle:public RoadVehicle{/*....*/};

為了表述簡單,使用數組來實現。由淺入深的提出以下幾個方案:

方案一: 數組直接儲存物件

Vehicle parking_lot[1000];

AutoVehicle x = /*.....*/

parking_lot[num_vehicles++] = x;

這裡出現兩個問題:

(1) Vehicle 為抽象基類,類Vehicle本身不會有對象,因此定義對象數組也就不可行了。

(2) 即使去掉類Vehicle中的純虛函數,parking_lot 儲存的是衍生類別裁剪後的對象,而不是所有繼承自Vehicle類的對象的集合。

方案二:數組儲存指標

Vehicle* parking_lot[1000];

AutoVehicle x = /*...*/;

parking_lot[num_vehicles++] = &x;

這裡出現下面的問題:

我們儲存在parking_lot中的是指向x的指標,如果x是個局部變數,一但變數x沒有了,parking_lot就不知道指向什麼東西了。我們可以改進一下,放入parking_lot中的值,不是指向原對象的指標,而是指向它們的副本的指標。在釋放數組的時候,也釋放其中所指向的全部對象。上面的代碼可以改寫為:

AutoVehicle x = /*...*/;

parking_lot[num_vehicles++] = AutoVehicle(x);

但是這樣改也帶來了動態記憶體管理的負擔。另外,只有當我們知道要放到parking_lot中的對象的靜態類型後,這種方法才能起作用。為瞭解決這個問題可以使用用虛複製函數, c++中處理未知類型的對象的方法就是使用虛函數。我們可以在類Vehicle中添加純虛函數: virtual Vehicle* copy() const = 0; 則在衍生類別AutoVehicle 中 copy() 函數可以如下實現:

Vehicle* AutoVehicle::copy() const

{

return new AutoVehicle(*this);

}

然後就可以這樣儲存了: parking_lot[num_vehicles++] = x->copy(); 這裡可以在運行時確定所要調用的copy函數。

方案三:定義代理類

方案二已經能較好的解決問題了,但是我們想避免顯示的處理記憶體配置,又能保持類Vehicle在運行時綁定。這裡採用代理類技術,就是定義一個行為和Vehicle對象相似,而又潛在地表示所有繼承自Vehicle類的對象的東西。每個Vehicle代理都代表某個繼承自Vehicle類的對象。只要該代理關聯著這個對象,該對象就肯定存在。簡單的實現了一下代理類,代碼如下:

#include <iostream>
using namespace std;

class Vehicle
{
public:
virtual double weight() const = 0;
virtual Vehicle* copy() = 0;
virtual ~Vehicle() {}
};

class AutoVehicle:public Vehicle
{
public:
double weight() const
{
cout << "AutoVehicle weight" << endl;
return 1;
}
Vehicle* copy()
{
return new AutoVehicle(*this);
}
};
class RoadVehicle:public Vehicle
{
public:
double weight() const
{
cout << "RoadVehicle weight" << endl;
return 2;
}
Vehicle* copy()
{
return new RoadVehicle(*this);
}
};

class VehicleSurrogate
{
public:
VehicleSurrogate();
VehicleSurrogate(Vehicle&);
~VehicleSurrogate();
VehicleSurrogate(const VehicleSurrogate&);
VehicleSurrogate& operator=(const VehicleSurrogate&);
double weight() const;
private:
Vehicle *vp;
};

VehicleSurrogate::VehicleSurrogate():vp(0){} //空代理

VehicleSurrogate::VehicleSurrogate(Vehicle &v):vp(v.copy()){}

VehicleSurrogate::~VehicleSurrogate()
{
delete vp;
}
VehicleSurrogate::VehicleSurrogate(const VehicleSurrogate &v):
vp(v.vp ? v.vp->copy() : 0){}
VehicleSurrogate& VehicleSurrogate::operator=(const VehicleSurrogate &v)
{
if(this != &v)
{
delete vp;
vp = (v.vp ? v.vp->copy() : 0);
}
return *this;
}
double VehicleSurrogate::weight() const
{
if(vp == 0)
{
cout << "empty VehicleSurrogate" << endl;
}
else
{
return vp->weight();
}
}

int main()
{
VehicleSurrogate parking_lot[1000];
AutoVehicle x;
int num_vehicles = 0;
parking_lot[num_vehicles++] = x;
parking_lot[0].weight();

RoadVehicle y;
parking_lot[num_vehicles++] = VehicleSurrogate(y);
parking_lot[1].weight();
return 0;
}

個人感覺代理類最主要的好處就是隱藏的記憶體的分配,方案二中copy就已經可以實現了,只不過看起來不是那麼順眼。代理類用類來表示概念,通過在容器中代理對象而不是對象本身,解決了我們的問題。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.