?? ex16.cpp
字號:
//第16章 數據的共享和流通
//[例16.1]深拷貝方式
#include <stdio.h>
#include<string.h>
class CDeep
{ public: int n; //描述動態數組的動態維數
int *p; //指針成員用于定位動態數組
CDeep(int) ;
~CDeep();
CDeep(const CDeep& r) ; //提交定制的拷貝構造函數
CDeep& operator=(const CDeep& r); //提交定制的等號運算符函數
};
CDeep::~CDeep()
{ static int s_num=1;
printf("%d.~CDeep()\t",s_num++);
delete [] p;
}
CDeep::CDeep(int k) //單參數入口的構造函數
{ n=k;
p=new int[n]; //定義動態數組int p[n]
}
CDeep& CDeep::operator=(const CDeep& r) //定義等號賦值運算符函數
{ if(n!=r.n) //兩個深部數組長度不一致時
{ delete [] p; //釋放原來的數組空間
n=r.n; //設置兩個數組長度相等
p=new int[n]; //建立與源數組等長的獨立數組
} //確保目標數組擁有獨立的資源
memcpy(p,r.p,n*sizeof(int)); //拷貝動態資源的物理數據
return *this; //返回物理數據一致的當前對象
}
CDeep::CDeep(const CDeep& r) //拷貝構造函數
{ n=r.n; //當前數組維數等于源數組維數
p=new int[n]; //建立獨立的內存資源
memcpy(p,r.p,n*sizeof(int)); //物理數據全盤拷貝
}
void main()
{ CDeep a(2),d(3); //定義外層局部對象a,d
a.p[0]=1; d.p[0]=666; //對象a,d深部數組元素的賦值
{ CDeep b(d); //調用拷貝構造函數
a.p[0]=88;
b=a; //調用等號賦值運算符函數
printf("%d;",b.p[0]); //顯示內層局部對象的深部數組元素
} //b調用析構函數清理深部資源
printf("%d;",d.p[0]); //顯示d深部數組元素a.p[0的值
printf("b fade out away;\t"); //記錄b淡出的標記
printf("%d;",a.p[0]); //顯示a深部數組元素a.p[0的值
}
//[例16.2] const對象與只讀成員函數。
#include<stdio.h>
struct CPoint { long x; long y; } ;
class CRect
{ public: CRect(int l, int t, int r, int b);
CPoint& TopLeft(); // top-left point的引用返回
const CPoint& TopLeft() const; //const reference to the top-left point
private: long left; long top;
long right; long bottom;
};
inline CRect::CRect(int l, int t, int r, int b)
{ left = l; top = t; right = r; bottom = b; }
inline CPoint& CRect::TopLeft() { return *((CPoint*)this); }
inline const CPoint& CRect::TopLeft() const
{ // 返回引用的只讀函數需雙邊const限制以維持內外一致
return *((CPoint*)this); //(CPoint*)this指針類型轉換
} //*this是CRect型的左值, *(( CPoint *) this)是CPoint型的左值
void main()
{ CRect r(10,20,30,40); //普通對象r調用構造函數
CPoint& rtl =r.TopLeft(); //聲明引用rtl簡化表達式的書寫
const CRect d(rtl.x+5,rtl.y+5,35,45); //只讀對象d調用構造函數
CPoint dtl(d.TopLeft()); //定義對象dtl,調用拷貝構造函數
printf("left=%d,top=%d\t",rtl.x,rtl.y);
printf("left=%d,top=%d\n",dtl.x,dtl.y);
} //輸出:left=10,top=20 left=15,top=25
//[例16.3] volatile關鍵字的用法
#include <stdio.h>
class B
{ volatile int m_n;
public: B(int v=1){ m_n=v; }
void Set(int n) volatile { m_n=n; }
void Show() const { printf("Show()const; n=%d\n",m_n);}
void Show() volatile { printf("Show() volatile; n=%d\n",m_n);}
void Show() { printf("Show() ;n=%d\n",m_n); }
};
void main() /*程序輸出結果: */
{ const B c; c.Show(); /*Show() const; n=1 */
volatile B v(2); v.Show(); /*Show() volatile; n=2*/
v.Set(3); v.Show(); /*Show() volatile; n=3 */
B x(4); x.Show(); /*Show() ; n=4 */
}
//[例16.4] mutable關鍵字注冊絕對可變的成員
#include <stdio.h>
class CType { public: mutable long v; long n; };
void main()
{ const CType cobj={1,2};printf("cobj={%d,%d};\t",cobj.v,cobj.n);
cobj.v=8; printf("cobj={%d,%d};\n",cobj.v,cobj.n);
//cobj.n=2; error : l-value specifies const object
} //輸出結果:cobj={1,2}; cobj={8,2};
//[例16.5]友元函數將類回歸到經典的公共訪問性質的結構
#include <stdio.h>
struct S{int e;}; //結構成員e是公共訪問性質
class B;
class A
{ private: int a;
public: void add(B& ); //成員函數中B& 型的形參要求前置說明
friend void swap(A*,B& ); //聲明全局函數swap是A類的友元函數
int& Ea(){return a;} //公共成員函數Ea等價地導出私有成員a
};
class B //訪問控制屬性不影響friend
{ friend void swap(A *p,B& r); //聲明全局函數swap為 B類的友元函數
private: int b;
friend void A::add(B& r); //A類的成員函數add是B類的友元函數
public: int& Eb(){return b;} //公共成員函數Eb等價地導出私有成員b
};
void PublicB(S *p,B& r) //B&形參 r只能訪問公共成員Eb
{ r.Eb()=1; //不能訪問私有成員b
// p->e=r.b; //error 'b' : cannot access private member
}
void swap(A *p,B& r) // 全局函數swap是類A類B這兩個類的友元函數
{ int t=p->a; //A*型形參p訪問A類的任意成員
p->a=r.b; r.b=t; // B&型形參r訪問B類的任意成員
}
void A::add(B& r)
{ // add是類B的友元函數
a+=r.b; //因此B&型形參r可以訪問其私有成員
}
void main() { A x; x.Ea()=1; B y; y.Eb()=2;
x.add(y); swap(&x,y);
printf("%d,%d\n",x.Ea(),y.Eb()); } //輸出2,3
// [例16.6]友元類B將當前類A視為一個公共訪問控制屬性的結構
#include <stdio.h>
class B;
class A //聲明類B為類A的友元類其含義就是
{ friend class B; //允許類B將類A當作一個公共的結構
private: int m_a;
A(int k=0){m_a=k;} //私有的全缺省值的構造函數
public: friend void g_f(); //聲明全局友元函數g_f
void Show(){printf("m_a=%d\t",m_a);}
};
class B
{ int m_b;
A a; //在類B中聲明一個類A的嵌入對象a
public:B(int k=1){ m_b=k; a.m_a=1+k; } //嵌入對象a訪問私有成員m_a
A& Add(A* ); //B類的成員函數是類A的友元函數
};
A& B::Add(A* p) // A*型指針入口,A&型引用返回
{ p->m_a+= a.m_a+m_b; // p訪問類A的私有成員m_a
return *p;
}
A* pa; //定義全局指針以導出靜態局部對象d
void g_f() // g_f()全局函數是A類的友元函數
{ A a; //定義局部對象調用私有的構造函數
a.m_a=1; //圓點運算符訪問對象的私有成員
a.Show();
static A d(100); //定義靜態的局部對象d
pa=&d; //全局指針指向靜態對象d
}
void main()
{ g_f(); //調用全局函數
B b; //定義對象b
b.Add(pa).Show(); //b.Add(pa)的結果就是靜態局部對象d
} //輸出:m_a=1,m_a=103
///[例16.7]靜態成員變量的聲明、定義和使用
#include <stdio.h>
static long* pa; //定義一個封裝文件內的靜態的全局指針pa
class CType
{ public: //公有訪問屬性:
static int data; //靜態成員聲明語句遵守不賦初始值的規則
CType(int n=1){ m_n=n;data++; } //靜態成員data記錄誕生對象的個數
static void f() //靜態成員函數內置定義
{ // 靜態成員sa的地址是一個常規的long*型的地址
pa=sa; //靜態的全局指針pa初始化為保護屬性的sa
} //對pa[k]的操作就是對于CType::sa[k]的操作,但pa[k]可以在外部訪問
protected: static long sa[]; //靜態成員聲明語句不涉及其內存分配
private: int m_n;
};
int CType::data; //相當于 int CType::data=0;
long CType::sa[]={20,30,40}; //此時補充數組的完備信息
void main()
{ CType::data=0;
printf("%d,static data=%d\t",sizeof(CType),CType::data);
CType::f(); //調用靜態成員函數pa= CType::sa;
printf("pa[0]=%d,pa[1]=%d,pa[2]=%d\n",pa[0],pa[1],pa[2]);
} //輸出:4,static data=0 pa[0]=20,pa[1]=30,pa[2]=40
//// [例16.8] 靜態成員對象實質上是全局對象, 靜態成員函數實質上是全局函數
# include<stdio.h>
class A
{ private: //將全局對象static A a平移到類域中
static A a; //靜態私有成員是獨立于當前類的對象
int m_n; //當前類實例的成員變量
A(int n) //私有的構造函數禁止外部定義對象
{ m_n=n; printf("call A::A();\t"); }
public:
static A& GetStatic(); //返回對象引用的靜態成員函數
int GetNum(){return this->m_n;} //公共的成員函數取私有數據狀態
};
inline A& A::GetStatic()//定義inline型的靜態成員函數
{return a;} //內聯映射使得函數調用A::GetStatic()等價于a
A A::a(10); //文件范圍內定義名稱為A::a的靜態私有成員對象
void main()
{ printf("Here is in main scope\t");
printf("m_n=%d\t",A::GetStatic().GetNum());
A& (*pf)()=A::GetStatic; //常規函數指針pf獲得靜態成員函數的地址
printf("m_n=%d\n",pf().GetNum());//pf()的結果就是對象A::a
} //輸出:call A::A(); Here is in main scope m_n=10 m_n=10
/// [例16.9]指向數據成員的指針,靜態成員函數的地址屬性同等于全局函數的地址屬性
#include <stdio.h>
class CType
{ public:static void Setpm(int CType::* & ,int k);//靜態成員函數聲明
void Set(int CType::*& pm,int k){Setpm(pm,k);this->*pm+=k;}
CType(int x=10,int y=20) { m_t1=x; m_t2=y; }
void Show() { printf("m_t1=%d,m_t2=%d\t",m_t1,m_t2);}
public: int m_t1;
private: int m_t2;
};
void CType::Setpm( int CType::*& pm, int k) //引用形參pm便于數據的傳遞
{ //開關變量k用于分流指向成員的指針賦值
if(k==1) pm=&CType::m_t1; //入口局部指針pm關聯公共變量
else pm=&CType::m_t2; //指向成員的指針pm關聯私有變量
} //靜態成員函數CType::Setpm實質上是全局函數
void (*Setpm)( int CType::*& ,int)= CType::Setpm;//定義一個常規函數指針Setpm
void main() // Setpm 指向靜態成員函數CType::Setpm
{ int CType::* pm; //定義指向成員數據的局部指針pm
CType::Setpm(pm,1); //調用靜態成員函數CType::Setpm,得pm=&CType::m_t1
CType a; //定義局部對象a(10,20)
a.Show(); //顯示默認的設置值
a.*pm+=10; //成員指針訪問公共的成員變量 m_t1
Setpm(pm,2); //常規函數指針間接調用靜態成員函數,得到pm=&CType::m_t2;
a.*pm+=20; //成員指針訪問私有的成員變量m_t2
a.Set(pm,1); // 得到pm=&CType::m_t1;a.*pm+=1;
a.Show(); //顯示運算后的結果
} // 輸出:m_t1=10,m_t2=20 m_t1=21,m_t2=40
// [例16.10]指向成員函數的指針
#include <stdio.h>
class CType; typedef int (CType::*PFM)(int);
class CType
{ public: static void Setpfm(PFM & pfm,int); //靜態成員函數設置成員指針
CType(int x=0){pfm(x);}
void Show(){ printf("m_x=%d\t",m_x); }
int pfm(int x){m_x=x; return 2;} //公共屬性的成員函數pfm
private: int Add(int x){m_x+=x; return 1;} //私有成員函數
int m_x;
};
void CType::Setpfm(PFM & pfm,int num) //成員函數指針引用形參完成
{ switch(num) //取成員函數地址的工作
{case 1: pfm=&CType::Add;break; //獲取私有成員函數的地址
default: pfm=&CType::pfm;break; //獲取公共成員函數的地址
}
}
int (CType::*gpfm)(int)=&CType::pfm; //全局性的指向成員函數的指針gpfm
// gpfm指向公共的成員函數
void main()
{ CType* pthis=new CType();
(pthis->*gpfm)(10); pthis->Show();
PFM pfm; //定義一個PFM型的局部變量pfm
CType::Setpfm(pfm,1); // 1.pfm=&CType:: Add;
(pthis->*pfm)(20); pthis->Show(); //(pthis->*pfm)(20) 等價于pthis-> Add (20)
CType::Setpfm(pfm,2); // 2.pfm=&CType:: pfm;
(pthis->*pfm)(3); pthis->Show(); // (pthis->*pfm)(3)等價于pthis->pfm(3)
pthis->pfm(4); pthis->Show();
} //輸出:m_x=10 m_x=30 m_x=3, m_x=4
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -