1. 程式人生 > >C++ 中讓物件的拷貝成為 顯式 的

C++ 中讓物件的拷貝成為 顯式 的

C++中物件的拷貝一般使用拷貝建構函式,從而物件的拷貝大多是隱式的,使用拷貝建構函式的隱式拷貝很方便,但是編譯器無法識別不必要的拷貝,雖然我們人類可以識別這些不必要的拷貝,比如在寫函式原型時,忘了加&,就會引發一個這樣的非必要拷貝。

如果這種情況很嚴重,我們可以禁用拷貝建構函式和賦值函式(宣告成private),然後再提供一個顯式拷貝函式,如:

class HeavyObject { HeavyObject(const HeavyObject&); HeavyObject& operator=(const HeavyObject&); public: void clone_to(HeavyObject& dest) const; // more... };

這種方法的確可以work,但看上去很不自然,比如:

HeavyObject x, y; // ... y.clone_to(x); // copy y to x // 其實我們更習慣這樣的表達: x = y.clone(); x = y.clone(); 在形式上很自然,但是實現卻不容易(在C++11中實現要容易點,讓 x 接受 && 即可)。

但的確可以實現:在 C++98 標準中,如果一個函式返回一個非 Primitive 的值物件,那麼這個物件不能被 bind 到非 const 引用上, 但是可以被修改

我們可以利用標準的這個特點:

template<class T> struct Ref2 : T {}; template<class T> struct Ref1 { // 作為返回值物件,Ref1 可以被修改,但不能繫結到 Ref1& 上 T val; Ref1(const T& y) : val(y) {} operator Ref2<T>&() // this is a non-const member function { return static_cast<Ref2<T>&>(val); } }; class HeavyObject { friend struct Ref1<HeavyObject>; // for Ref1 accessing the private copy-cons HeavyObject(const HeavyObject&); HeavyObject& operator=(const HeavyObject&); public: HeavyObject() {} void swap(HeavyObject& y) { /*non-throw*/ } void operator=(Ref2<HeavyObject>& y) { // prohibit chained assign this->swap(y); // y is the object created by clone } Ref1<HeavyObject> clone() const { // copy-cons is private and has implementation // assume return value optimization is enabled return Ref1<HeavyObject>(*this); } // more... };

當執行 x = y.clone() 時,clone 呼叫Ref1(const HeavyObject& y) 建立一個臨時物件並按值

返回,該物件不能 bind 到 non-const reference,但可以被修改!

接下來該物件被傳給HeavyObject::operator=,但該 operator= 只接受 Ref2& 或 const HeavyObject&,於是,編譯器需要呼叫一個 user defined type conversion, 在這裡,就是Ref1::operator Ref2&,該函式是 non-const,可以被呼叫(記得前面說的:不能 bind 到 non-const reference,但可以被修改,從而就可以呼叫 non-const member function)……

於是,接下來的事情就很簡單了……

相關推薦

C++ 物件拷貝成為

C++中物件的拷貝一般使用拷貝建構函式,從而物件的拷貝大多是隱式的,使用拷貝建構函式的隱式拷貝很方便,但是編譯器無法識別不必要的拷貝,雖然我們人類可以識別這些不必要的拷貝,比如在寫函式原型時,忘了加&,就會引發一個這樣的非必要拷貝。 如果這種情況很嚴重,我們可以禁用拷

C++函數模板,具體化,實例化:

程序 使用 集合 typename 內容 方法 區分 bsp 代碼 函數模板 形如: template<typename T> //沒有分號 void func(T &a,T &b); 稱為函數模板,其中,template和typename為關

JavaSE8基礎 子類構造函數寫super語句去指定父類的構造函數

ext rgs void gen light 顯式 結果 cast 基礎 os :windows7 x64 jdk:jdk-8u131-windows-x64 ide:Eclipse Oxygen Release (4.7.0) 代碼:

探究Objective-C關聯物件原理

一、實際問題 1.提出問題 首先,一切都要從一個問題開始:在Objective-C中,能否在Category中為類新增屬性及對應的例項變數? 該題的答案是:不能。 2.分析解答 為什麼不能通過Category來為Objective-C的類新增屬性及對應的例項變數

c++指向物件的指標為NULL時可以呼叫物件成員函式嗎

問題貌似有點奇怪,指標都為NULL了怎麼還可使用?但其實不是的,可以看以下程式碼: #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 void

C++人忽視的左值和右值

前言 為了瞭解C++11的新特性右值引用,不得不重新認識一下左右值。學習之初,最快的理解,莫過於望文生義了,右值那就是賦值號右邊的值,左值就是賦值號左邊的值。在中學的數學的學習中,我們理解的是,左值等價於等號左邊的值,右值等價於等號右邊的值;當我們繼續學習C語言時,等號=不再叫等號,蓋頭換面叫做

C++的深拷貝與淺拷貝

淺拷貝問題丟擲: #define _CRT_SECURE_NO_WARNINGS #include "iostream" using namespace std; /* 淺拷貝問題丟擲 */ cl

C++string物件的比較

比較原則: 例:string str1 = "Hello";        string str2 = "Hello World";        string str3 = "Hiya"; 1、若兩個string物件長度不同,而且較短的string物件的每個字元都與

C++宣告物件與new物件的區別

new出來的物件是直接放在堆上,而宣告一個物件是放在棧中。換句話說,new出來的物件的生命週期是全域性的,譬如在一個函式塊裡new一個物件,可以將該物件的指標返回回去,該物件依舊存在。而宣告的物件的生命週期只存在於聲明瞭該物件的函式塊中,如果返回該宣告的物件,將會返回一個已經

c++物件直接作為函式引數所引起的問題。

這兩天在寫一個視訊轉換的程式,將H263/264編碼的視訊封裝成mov格式,用c++實現。 Wiki上說Apple的mov格式是典型的over engineering,設計的非常複雜,各種資訊使用atom原子封裝,一個atom裡面遞迴地巢狀著另外一個atom,atom的種類

為什麼C++物件之間能夠進行賦值?

C++中所有的 型別 變數都是 類 物件的形式,那麼C++中類物件之間是怎麼進行賦值操作的呢? 主要是因為C++存在拷貝建構函式,拷貝建構函式的定義如下所示: 類名(類名 &); 具體的例項如下所示: #include <iostream> using

C#新增物件到ArrayList的程式碼

把開發過程中比較好的一些程式碼段做個備份,下面程式碼是關於C#中新增物件到ArrayList的程式碼。 ArrayList alcollect = new ArrayList();string str = "learn csharp";alcollect.Add(str);alcollect.Add("he

【SQL】IDENTITY_INSERT 設定為 OFF 時,不能為表 '***' 的標識列插入值。

【前言】 今天在處理牛腩新增新聞資料時,將其中一天記錄複製為INsert 語句,在執行語句是報錯如下: 【解決方案】 在執行插入語句前,首先執行 -允許將顯式值插入表的標識列中 ON-允許 off - 不允許 SET IDENTITY_INS

C++面向物件的思想

   C++語言是C語言的拓展,C語言是面向過程的,C++在C的基礎上增加了面向物件的方法。         所謂面向過程的程式設計思想,就是分析解決問題的步驟,將這些步驟用一個個函式實現,最後一個個呼叫。         所謂面向物件的程式設計思想,就是將任何事物都

C++建構函式詳解及呼叫建構函式(explicit)

一. 什麼是拷貝建構函式 首先對於普通型別的物件來說,它們之間的複製是很簡單的,例如: int a = 100;   int b = a;  而類物件與普通物件不同,類物件內部結構一般較為複雜,存在各種成員變數。 下面看一個類物件拷貝的簡單例子。 #include &

C++物件指標和物件引用

在C++中,可以說明指向類的資料成員和成員函式的指標。    指向資料成員的指標格式如下:    <型別說明符><類名>::*<指標名>    指向成員函式的指標格式如下:    <型別說明符>(<類名>::*<

c++面對物件3個特徵,以及面對物件和麵對過程的優缺點。

c++中面對物件3個特徵: 1.封裝性:倆方面的意義,一是將基本資料和對此進行操作的過程和函式結合起來,形成一個物件,物件之間相互獨立,互不干擾。二是物件將對外公開的一個介面,而將具體的細節隱藏起來,保證資料的安全性。2.繼承性:利用一個已經有的類建立一個新的類,子類從父類

C++函式返回字串

轉:http://379910987.blog.163.com/blog/static/3352379720111026101835400/ char* Alphabet(int n){    char* pStr=new char[n+1];//last one

js 物件拷貝

js 中物件的拷貝很常見,特別是在面試中很常見 一: 物件淺拷貝與深拷貝和物件引用的區別 var a= {name:'anikin'} var b = jsons a == b // true b.name == 'jack' a.name //

C++建立物件間訊息連線的一種系統方法——回撥函式

C++中建立物件間訊息連線的一種系統方法——回撥函式作者:項飛 用過C++進行過面向物件程式設計的使用者都知道,程式中的物件很少單獨存在。不考慮物件間的相互作用幾乎是不可能的。所以,標識物件間的關係或建立物件間的訊息連線是面向物件程式設計的一項重要任務。本文著重從C++程式