#
前段時間讀了一本書《C++沉思錄》,偶有感,摘錄如下:
模板和泛型算法(摘自 《c++沉思錄》):
一個特例:
1.假設(shè)我們希望從整數(shù)數(shù)組中找到第一個等于某給定值的元素.編寫如下代碼:
const int*
find1(const int* array, int n, int x)
{
const int *p = array;
for( int i = 0; i < n; i++)
{
if(*p==x)
return p;
++p;
}
return 0;
}
2.泛型化元素類型:
用類型T來表示整型等,適當?shù)臅r候可以把const也包含在T中,得到如下函數(shù).
template<class T>
T* find2(T* array, int n, constT& x)
{
T* p = array;
for(int i=0; i<n; i++)
{
if(*p==x)
return p;
++p;
}
return 0;
}
3.推遲計數(shù).
為了避免預(yù)先知道有多少個元素,我們改變函數(shù),使它接受指向第一個元素和最后一個元素之后元素的指針.
template<class T>
T* find3(T* array, T* beyond, constT& x)
{
T* p = array;
while(p!=beyond)
{
if(*p ==x)
return x;
++p;
}
return 0;
}
用!=而不用<來判斷循環(huán)結(jié)束并不是偶然.從某種角度來說,兩者沒有區(qū)別,如果find3的輸入有意義,則p就小于beyond,直到它們相等為止.但是,由<加以總體排序的類型通常也能用!=來進行比較.另一方面,考慮一下我們以后可能會用到來代替指針的類型,他們可以很好地定義!=,但不一定能定義<.此時,使用<就是一個不合理的假設(shè).
另外,我們還假設(shè)了,0可以轉(zhuǎn)換成一個與其他所有的值不同的指針值.我們稍微做一點改變,以避免這種假設(shè):如果程序中要找的值沒找到,它就返回beyond而不是0.
template<class T>
T* find4(T* array, T* beyond, constT& x)
{
T* p = array;
while(p!=beyond)
{
if(*p ==x)
return x;
++p;
}
return beyond;
}
因為程序要么返回適當?shù)腡*, 要么返回beyond.故程序代碼可以被修改如下:
template<class T>
T* find5(T* array, T* beyond, constT& x)
{
T* p = array;
while(p!=beyond && *p != x)
++p;
return p;
}
4.地址的獨立性
到目前為止,我們還是依賴于傳遞來的指針,該指針要指向要查找的數(shù)據(jù)的開頭.但是如果仔細分析一下,會發(fā)現(xiàn)我們只依賴于指針的某些保留特性:
1)可以把指針當參數(shù)接收,并把它們作為結(jié)果返回.
2)可以比較指針是否相等.
3)可以解除引用,以便得到值:*p.
4)可以遞增,以指向下一個元素.
只要符合上述條件的類型即可,不一定是指針類型.假設(shè)把T*作為模板參數(shù),我們就取消了對指針的依賴:
template<class P,class T>
T* find6(P start, p beyond, constT& x)
{
while(start !=beyond && *start != x)
++start;
return start;
}
我們已經(jīng)完全剔除了函數(shù)中關(guān)于具體類型的信息.根本沒有要求p是指針,只要求p滿足上述的四個特性.
在C++中,通過提供構(gòu)造函數(shù)、析構(gòu)函數(shù)來對處理資源的獲取、釋放。
通過C++的這種機制,我們可以很方便地處理C++中的加鎖同步機制。把鎖對象作為Guard對象的一個成員(m_lock),然后在Guard對象的構(gòu)造中對m_lock進行加鎖:m_lock.acquire(),在Guard對象的析構(gòu)函數(shù)中進行解鎖:m_lock.release()。先給出代碼實例如下:
template <class T>
class Guard
{
public :
Guard(const T & lock);
virtual ~Guard();
private:
const T & m_lock;
};
template <class T>
Guard<T>::Guard(const T & lock) :
m_lock(lock)
{
m_lock.acquire();
}
template <class T>
Guard<T>::~Guard()
{
m_lock.release();
}
我們可以在應(yīng)用程序中這樣使用它:
void testFunc(.....)
{
Guard<MutexWrapper> guard(mutex);
...
}
在剛進入函數(shù)testFun(...),創(chuàng)建guard對象,并自動對mutex進行加鎖,對特定數(shù)據(jù)(resource)進行保護。當應(yīng)用離開testFunc函數(shù)模塊時,根據(jù)guard對象的作用域和生命周期,此時guard對象的析構(gòu)函數(shù)將被調(diào)用,因此將自動對mutex進行解鎖。在此之后應(yīng)用的其他線程將可以訪問以前被mutex進行保護起來的資源。
利用上面的方法,我們可以包對資源的同步訪問和訪問控制交給C++的編譯器,而不需要進行人工干預(yù),從而減輕應(yīng)用開發(fā)人員的工作負擔。
C++中類包含三種成員訪問說明符:public, private 和 protected.
在程序能訪問類對象的任何地方都可以訪問任何在成員訪問說明符public后面聲明的數(shù)據(jù)成員和成員函數(shù).成員訪問符private后面的數(shù)據(jù)成員和成員函數(shù)只能由該類的成員函數(shù)或友元訪問.基類的protected成員只能被基類的成員和友元已及派生類的成員和友元訪問.
在C++中還存在三中繼承方式:public, private, protected.
對于它們的論述可以在任意一本關(guān)于C++的書中都可以找到.大家對public繼承都比較熟悉.但我們偶爾也會看到private繼承.private繼承時基類中的public,private成員變成派生類中的private成員.基類中的private成員在派生類中隱藏.
這里簡單介紹一下以下兩種情況的異同:
(1)B private 繼承A
(2)A是B的一個私有成員的異同.
相同點:A的接口(public 成員函數(shù))都只對B開放,不對外開放.
不同點:在(1)中A的public, protected成員都為B的private成員,B的成員函數(shù)可以直接訪問.在(2)中A的成員都不是B的成員,并且B不能訪問A的protected成員,要訪問A的public成員也要借助A的對象.
下面再講一些編譯器在構(gòu)造類時所采取的缺省操作:
1.如果類沒有聲明構(gòu)造函數(shù),編譯器會聲明一個默認構(gòu)造函數(shù).
2.如果沒有聲明拷貝構(gòu)造函數(shù),編譯器會隱式地生成一個.
3.如果沒有聲明賦值操作符,編譯器會隱式地生成一個.
4.如果沒有聲明析構(gòu)函數(shù),編譯器會隱式地生成一個.
隱式生成的函數(shù)都是public的.
如果接受一個副本是有效的行為,就該聲明并定義拷貝構(gòu)造函數(shù)和賦值操作符.如果接受一個副本是禁止的,你可以將拷貝構(gòu)造函數(shù)和賦值操作符聲明為private,并且不實現(xiàn)它們,這樣可以阻止編譯器生成缺省的操作,從而防止客戶復(fù)制類對象.
下面是代碼實例:
class test{
};
該類中不包含任何成員,也沒聲明任何方法.編譯器會缺省生成下列方法:
test::test()
{
}
test::~test()
{
}
test::test(const test& rt)
{
...
}
test& test::operator=(const test& rt)
{
...
}
這些方法都是public的.
如果想阻止編譯器生成缺省的拷貝構(gòu)造函數(shù),和賦值操作,可以進行如下操作:
class test{
private:
test(test& rt); // 該方法被定義為private,并且不被實現(xiàn).
test& operator=(test& rt); // 該方法被定義為private,并且不被實現(xiàn).
};
在應(yīng)用開發(fā)構(gòu)成中,我們經(jīng)常在程序中加入一些打印語句,來對程序的執(zhí)行流進行跟蹤.在C或C++中可以利用下列語句來實現(xiàn):
(1)
printf("enter %s\n",(char *)funcName);
或
cout<<"enter "<< s_funcName << endl;
但這樣處理有點不足,就是該語句只輸出到標準輸出上,我有時希望這些輸出被定向到特定文件,輸出成日志.為此,我們可以把這些函數(shù)進行包裝,把輸出流ostream(標準輸出或文件輸出)作為包裝函數(shù)的一個參數(shù):
(2)
printWrap(ostream out,format, args);
注:此處的args, format表示要輸出的參數(shù)和相應(yīng)的參數(shù)格式.
當然我們還可以對它進行進一步的改進:在該函數(shù)中,加入預(yù)定以的符號常量__LINE__(當前源代碼行的行號,為整數(shù)常量),__FILE__(假定的源文件名,某個字符串).這樣我們可以知道程序運行到了那個源文件,并且那一行.
現(xiàn)在(2)中的處理方式比(1)中處理方式已經(jīng)有明顯的改善了.
但這種方式還稍微有點不足.當我們想要跟蹤一個函數(shù)的執(zhí)行,即知到執(zhí)行流進入某函數(shù),何時離開某函數(shù)時,這種處理方式有點不足.每個函數(shù)都有一個入口,但可能有多個出口,這樣就需要在每個入口和出口處加上printWrap(ostream out,args)語句,并且在C++中,當執(zhí)行流遇到異常退出該函數(shù)時,可能有些printWrap語句并沒有被執(zhí)行,從而沒有輸出記錄.
為此,我們可以對(2)進行進一步改進.我們可以設(shè)計一個類,在該類對象的構(gòu)造函數(shù),析構(gòu)函數(shù)中進行輸出.在函數(shù)的入口處,調(diào)用對象的構(gòu)造函數(shù)進行輸出;在函數(shù)的出口處,或異常退出時,調(diào)用對象的析構(gòu)函數(shù)進行輸出.
我們可以把該類簡單總結(jié)如下:
(3)
class Trace{
public:
Trace(int iDebugLevel,ostream out, format,args) { cout <<"Hello\n";}
~Trace() { cout << " Goodby\n";}
int getDebugLevel();
private:
...
int iDebugLevel;
ostream m_out;
};
注: 我們可以用printWrap(..)替換cout << ....。printWrap中的輸出流在Trace的構(gòu)造函數(shù)中傳到Trace實例中,并被保存。
我們還可以對它進行一點改進,以提高它的性能。因為采用上面的對象。則每次都會進行輸出或進行日志記錄.我們可以通過構(gòu)造函數(shù)在Trace的實例中,設(shè)置一個iDebugLevel變量和ostream。并在系統(tǒng)中設(shè)置一個統(tǒng)一的debugLevel.在每次進行輸出時進行iDebugLevel, debugLevel比較,如果iDebugLevel <= debugLevel, 則進行輸出,否則則不進行輸出.
前段時間,碰到了C,C++混合編程的需求,經(jīng)過努力,順利解決問題.現(xiàn)把這方面的知識做一下簡單的總結(jié):
1.當C++文件要用到C語言中的函數(shù)代碼時,采用下屬方法即可:
在C++中的.h文件或.cpp文件中加入下列代碼,
#define LINT_ARGS 1
extern "C" {
#include "system.h"
}
然后在代碼中直接調(diào)用這些函數(shù)即可.
注解:
1.1 LINT_ARGS 1表示在檢查C語言中的函數(shù)原型時,要對函數(shù)原型的參數(shù)進行檢查.
1.2. "{ }" 中包含的頭文件為C語言中的頭文件.
1.3.extern "C" 告訴鏈接器,這些頭文件中的函數(shù)被當做C語言中的函數(shù)來處理.
下面以一個實例加以說明:
下面為一個C語言的頭文件(sysgct.h):
#ifdef LINT_ARGS
int GCT_send(unsigned int task_id, HDR *h);
......
#else
int GCT_send();
......
#endif
~
in file MapBaseReq.cpp 文件中
#include ....
extern "C"
{
#include "sysgct.h"
}
void
MapBaseReq::sendPdu(const BasePdu_var& thePduP)
{
...
if (GCT_send(m->hdr.dst, (HDR *)m) != 0)
{
relm((HDR *)m);
SETERR1(errSWErrorMsg, "sendPdu(): GCT_send() Failed");
}
...
}
2.當C文件要用到C++語言某個類中的方法時,可以采用下列方法:
2.1 在cpp文件中用下列方式定義函數(shù):
extern "C" returnType FunName(parameters list).
2.2 然后在相應(yīng)的頭文件中進行聲明:
extern returnType FunName(parameters list);
2.3 在相應(yīng)的.c文件中包含該頭文件,然后直接利用相應(yīng)的函數(shù)即可.
下面給出實例.
2.4 cpp文件
#include <iostream>
#include <iomanip>
#include "TTDebug.h"
using namespace std;
extern "C"
{
#include "Utility.h"
}
static int display_hex_buffer(unsigned char* buffer, unsigned char* ptr,int len);
extern "C" void tDebug_traceFunc(int level, char* trace)
{
TDEBUG_TRACEFUNC(level,trace);
}
extern "C" void nDebug(int level, unsigned char* args, int iLen, int cid)
{
unsigned char buf[512];
if(0 != TTDebug::instance() && TTDebug::instance()->isTTDebugOn(level))
{
/* Check whether the current thread already holds the mutex lock */
LockGuard<MutexWrapper> guard(TTDebug::instance()->mutex());
TTDebug::instance()->traceStart(level, __FILE__, __LINE__);
memset(buf,0,512);
display_hex_buffer(buf,args,iLen);
TTDebug::instance()->outStream() << "Send Msg(0-0x" << setw(4) << setfill('0') << hex << cid <<"):0x" << buf;
TTDebug::instance()->traceEnd();
}
}
2.5 .h 文件
#ifndef __UTILITY_H
#define __UTILITY_H
extern void tDebug_traceFunc(int level, char* trace);
extern void nDebug(int level, unsigned char* args,int iLen, int cid);
#endif
2.6 cpp文件中定義的函數(shù)在c文件中調(diào)用實例
在test.c文件中:
...
int ctu_ent(msg,pInt)
MSG* msg;
int *pInt;
{
tDebug_traceFunc(10,"ctu ctu_ent");
HDR *h;
MSG *m;
...
}
...
在運用JAVA,C++等面向?qū)ο蟮恼Z言進行開發(fā)的時候,不可避免地要用到繼承.即從一個父類(P)派生出相應(yīng)的子類(C).在開發(fā)應(yīng)用的時候,我們可以僅從單個類的角度來考慮繼承或派生.但是我們可以進一步對它進行引申.比如我們可以用基類(或純抽象類,JAVA中的接口)來開發(fā)處理某類業(yè)務(wù)的抽象架構(gòu)或平臺,然后針對具體的應(yīng)用,我們派生出相應(yīng)的派生類,讓它們來完成具體業(yè)務(wù)的具體邏輯.
在C++中,基礎(chǔ)架購用基類寫就,但具體業(yè)務(wù)邏輯用派生類來實現(xiàn).為了做到這一點,我們必須在架構(gòu)中指向基類對象的指針(->操作符),并且定義相應(yīng)的虛函數(shù)(或純虛函數(shù)).這樣實現(xiàn)程序的動態(tài)多態(tài).這樣實現(xiàn)既滿足了面向?qū)ο笤O(shè)計的OCP原則(open-close principle).
在基礎(chǔ)架構(gòu)中可能還包含保存基類指針的容器,這些指針可能后來所賦之值是派生類的指針,并且考慮到對象的生命周期,這些對象應(yīng)該是通過NEW操作在heap上生成的對象,而不是在stack上保存的局部對象.為了保證這些對象的自動銷毀,不需要應(yīng)用開發(fā)人員的人工干預(yù),這些保存在容器中的指針最好是含有基類指針的智能指針SmartPointer,或者說是代理類.SmartPointer是代理類中的一種.
根據(jù)前一篇文章的分析,在應(yīng)用對對象指針的處理,采用了智能指針.但指向基類(P)的智能指針(SmartPp)與指向子類(C)的智能指針(SmartPc)不是父類與子類的關(guān)系,它們應(yīng)該是同一類的不同實例.因此還應(yīng)該對智能類定義如下操作,使之滿足轉(zhuǎn)型要求:
(1)從智能指針中獲取指向?qū)ο笾羔樀哪芰Γ?/div>
(2)根據(jù)指向?qū)ο蟮闹羔樕芍悄苤羔樀哪芰Γ?/div>
滿足這兩點,我們就可以從SmartPc中獲取pC(指向子類的指針),然后把它轉(zhuǎn)型成pP(指向父類的指針),然后再根據(jù)pP生成SmartPp,然后保存在基礎(chǔ)架構(gòu)的容器中.在實際應(yīng)用的過程中,會用到指向父類的指針,但此時它實際上是指向子類的指針,在程序運行的過程中,將用到動態(tài)多態(tài)性,即虛函數(shù)來處理相應(yīng)的應(yīng)用.
BTW(順便說一下),因為一般說來容器(MAP,vecotr,或數(shù)組)只能保存一種類型,另外又要用到運行時的多態(tài),最好保存指向基類對象的指針,而不直接保存對象,否則子對象將被切割,只保留父類部分,其余將被丟棄.另外為減少對對象管理的負擔,最好在容器中保存對象的代理對象.
1.淺論C++中的智能指針(Smart Pointer)
簡單地講,智能指針是用一個對象來對指針進行建模,使之具有指針的特性,跟指針具有相同含義的->,*操作.并且通過對象的構(gòu)造函數(shù)(獲取資源),析構(gòu)資源(釋放資源)來對資源進行管理,從而減少程序員對通過new操作獲取到的對象的生命周期進行管理的負擔.
根據(jù)《Moden C++ Design》, 我們可以構(gòu)造具有很多正交特性的智能指針。
1.1 C++中的智能指針與JAVA中的對象
前段時間跟朋友聊了些有關(guān)JAVA的東西,感覺上Java中的對象就是C++中的智能指針,但具有不同的資源釋放方式。在JAVA中,不能象C++中運用" A a;"語句聲明得到一個類(A)的事例a,而必須通過下列語句來獲得:Aa = new A.要在釋放a時,應(yīng)用必需通知
GC(垃圾收集功能)來釋放該實例所占用的資源。當然,JAVA中的對象有一小點同C++中的職能智能不同,因為在C++中指針不具有"."操作符,故智能指針一般也不提供"."操作符,但在Java中都是通過"."操作符對對象進行操作的,不過我們可以把C++中職能指針的"->"操作符與
Java中的"."操作符進行類比。
1.2 引用計數(shù)型智能指針
在C++中有一種常用的智能指針是引用計數(shù)型智能指針:RCSmartPtr. 它的實現(xiàn)基理如下:
首先,存在RCObject,即存在一個對象,該對象提供引用計數(shù)接口。
另外,要存在指向RCObject的RCSmartPtr對象,在RCSmartPtr對象的構(gòu)造過程中,把指向RCObject的指針作為參數(shù)傳入RCSmartPtr中。因此每增加一個RCSmartPtr對象,就多了一個指向RCObject的指針。RCSmartPtr可以通過調(diào)用RCObject的引用計數(shù)接口,增加RCObject
的引用計數(shù)。同樣的道理可以在RCSmartPtr對象的析構(gòu)函數(shù)中調(diào)用RCObject的引用記數(shù)接口來減少RCObject的引用記數(shù)。
第三,在對RCObject的引用計數(shù)進行操作時對引用計數(shù)進行檢查,如果引用計數(shù)為0,則RCObject將摧毀本身,從而釋放該對象所占用的資源。
通過這種方式,我們就可以把對資源的管理交給機器來管理,解除了對人工的倚賴。
精品久久久久久久久免费影院|
一本色道久久88综合日韩精品
|
国产精品久久久久久福利漫画|
97久久综合精品久久久综合|
国产精品xxxx国产喷水亚洲国产精品无码久久一区
|
久久久久久久久久久久中文字幕
|
久久精品国产色蜜蜜麻豆|
波多野结衣久久精品|
91精品国产综合久久精品|
要久久爱在线免费观看|
99久久精品费精品国产一区二区|
久久国产热这里只有精品|
日韩乱码人妻无码中文字幕久久
|
久久精品国产精品国产精品污|
久久久精品国产亚洲成人满18免费网站
|
久久国产免费观看精品3|
久久精品无码一区二区三区日韩|
色婷婷综合久久久久中文|
久久综合久久鬼色|
国产精品视频久久|
久久午夜免费视频|
国产亚洲精久久久久久无码AV|
国产精品久久精品|
久久精品水蜜桃av综合天堂|
欧美亚洲国产精品久久久久|
色婷婷综合久久久久中文字幕
|
三级三级久久三级久久|
精品久久久久久无码人妻热|
久久九九亚洲精品|
91精品国产色综合久久|
97久久久久人妻精品专区|
久久精品亚洲日本波多野结衣|
久久天天躁狠狠躁夜夜avapp|
精产国品久久一二三产区区别|
久久久WWW成人|
久久久精品波多野结衣|
久久久久国产|
久久久久九国产精品|
久久精品国产WWW456C0M|
亚洲成av人片不卡无码久久|
思思久久99热免费精品6|