日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++代理 Surrogate

發布時間:2023/12/20 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++代理 Surrogate 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

容器通常只能包含一種類型的對象,所以很難在容器中存儲對象本身。存儲指向對象的指針,雖然允許通過繼承來處理類型不同的問題(?多態性?),但是也增加了內存分配的額外負擔。所以我們通過定義名為?代理?的對象來解決該問題?。代理?運行起來和它所代表的對象基本相同,但是允許將整個派生層次壓縮在一個對象類型中。

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

class Vehicle { public:virtual double weight() const = 0;virtual void start() = 0;//... };class RoadVehicle:public Vehicle{/*...*/}; class AutoVehicle:public Vehicle{/*...*/}; class Aircraft:public Vehicle{/*...*/}; class Helicopter:public Vehicle{/*...*/};

可見Vehicle是一個抽象基類,有兩個純虛函數表示一些共有屬性。下面請看下面這句話為什么不能達到預期的效果:

Vehicle parking_lot[1000];

表面上看是由于Vehicle是一個抽象基類,因此,只有從類Vehicle派生出來的類才能實例化,類Vehicle本身不會有對象,自然也就不會有對象數組了。

???????但是,假設我們剔除了類Vehicle中的所有純虛函數,使其對象存在,那又會出現什么樣的情況呢?看下面的語句:

Automobile x=/*...*/;

parking_lot[num_vehicles++] = x;

把x賦給parking_lot的元素,會把x轉換成一個Vehicle對象,同時會丟失所有在Vehicle類中沒有的成員。該賦值語句還會把這個被剪裁了的對象復制到parking_lot數組中去。這樣,我們只能說parking_lot是Vehicle的集合,而不是所有繼承自Vehicle的對象的集合。

經典解決方案------提供一個間接層

最早的合適的間接層形式就是存儲指針,而不是對象本身:

Vehicle* parking_lot[1000];

然后,就有

Automobile x = /*...*/;

parking_lot[num_vehicles++] = &x;

這種方法解決了迫切的問題,但是也帶來了兩個新問題。

我們存儲在parking_lot中的是指向x的指針,在上例中是一個局部變量。這樣,一旦變量x沒有了【作用域】,parking_lot就不知道指向什么東西了。

我們可以這么變通一下,放入parking_lot中的值,不是指向原對象的指針,而是指向它們的副本的指針。當我們釋放parking_lot時,也釋放其中所指向的全部對象。

上述修改雖然不用存儲指向本地對象的指針,但是它也帶來了動態內存管理的負擔。另外,只有當我們知道要放到parking_lot中的對象的靜態類型后,這種方法才起作用。不知道又會怎樣呢?看下面的:

if(p != q)

{

?? delete parking_lot[p];

???parking_lot[p] = parking_lot[q];

}

這樣的話,parking_lot[p]和parking_lot[q]將指向相同的對象,這不是我們想要的。在看下面的行不行:

if(p != q)

{

?? delete parking_lot[p];

???parking_lot[p] = new Vehicle(*parking_lot[q]);

}

這樣我們又回到了前面的問題:沒有Vehicle類型的對象,即使有,也不是我們想要的(是經過剪裁后的對象)。

如何復制編譯時類型未知的對象-------虛復制函數

我們在上面的Vehicle類中加入一個合適的純虛函數:

class Vehicle?
{?
public:?
virtual double weight() const = 0;?
virtual void start() = 0;

virtual Vehicle* copy() const = 0;?
?//...?
};

接下來,在每個派生自Vehicle的類中添加一個新的成員函數copy。指導思想就是,如果vp指向某個繼承自Vehicle的不確定類的對象,那么vp->copy()會獲得一個指針,該指針指向該對象的一個新建的副本。例如:如果Truck繼承自(間接或直接)類Vehicle,則它的copy函數就類似于:

Vehicle* Truck::copy() const

{

??? return new Truck(*this);

}

當然,處理完一個對象后,需要清除該對象。要做到這一點,就必須確保類Vehicle有一個虛析構函數:

class Vehicle?
{?
public:?
virtual double weight() const = 0;?
virtual void start() = 0;

virtual Vehicle* copy() const = 0;

virtual ~Vehicle(){}?
?//...?
};?
有了上面的分析,下面我們就來定義代理類:

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

上述代理類有一個以const Vehicle&為參數的構造函數,這樣就能為任意繼承自Vehicle的類的對象創建代理了?(多態性,因為這里是引用參數)?。同時,代理類還有一個缺省構造函數,所以我們能夠創建VehicleSurrogate對象的數組。

然而,?缺省構造函數也給我們帶來了問題:如果Vehicle是個抽象基類,我們應該如何規定VehicleSurrogate的缺省操作呢?它所指向的對象的類型是什么呢?不可能是Vehicle,因為根本就沒有Vehicle對象。為了得到一個更好的方法,我們要引入行為類似于零指針的空代理的概念。能夠創建、銷毀和復制這樣的代理,但是進行其他的操作就視為出錯。

下面看各個函數的定義:

VehicleSurrogate::VehicleSurrogate():vp(0){}

VehicleSurrogate::VehicleSurrogate(const Vehicle& v):vp(v.copy()){}//非零的檢測室必要的,空代理

VehicleSurrogate::~VehicleSurrogate()

{

????? delete vp;//C++標準里面對一個空指針運用delete也是沒有問題的

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

}

下面就很容易定義我們的數組了:

VehicleSurrogate parking_lot[1000];

Automobile x;

parking_lot[num_vehicles++] = x;

最后一條語句就等價于

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

這個語句創建了一個關于對象x的副本,并將VehicleSurrogate對象綁定到該副本,然后將這個對象賦值給parking_lot的一個元素。當最后銷毀parking_lot數組時,所有這些副本也將被清除。?

總結

以上是生活随笔為你收集整理的C++代理 Surrogate的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。