• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            寶杉的博客

            UNIX/LINUX;ACE;SNMP;C++
            posts - 33, comments - 23, trackbacks - 0, articles - 0

            缺省值

            提高程序易用性,避免每次調用函數參數都相同的情況。

            缺省值只能出現在函數聲明中,不能在函數定義中。

            兩個原因:

            一是函數的實現(定義)本來就與參數是否有缺省值無關,所以沒有必要讓缺省值出現在函數的定義體中。

            二是參數的缺省值可能會改動,顯然修改函數的聲明比修改函數的定義要方便。

            規則:參數從后向前缺省

            正確的示例如下:

            void Foo(int x, int y=0, int z=0);

            錯誤的示例如下:

            void Foo(int x=0, int y, int z=0);  

            但要避免二義性

            C++exams\default_para

             

            運算符重載及其規則

            運算符即可定義為成員函數,也可定義為全局函數。

            規則如下:

            運算符

            規則

            所有的一元運算符

            建議重載為成員函數

            = () [] ->

            只能重載為成員函數

            += -= /= *= &= |= ~= %= >>= <<=

            建議重載為成員函數

            所有其它運算符

            建議重載為全局函數

             

            不能重載的運算符

            1)不能改變C++內部數據類型(如int,float等)的運算符。

            2)不能重載‘.’,因為‘.’在類中對任何成員都有意義,已經成為標準用法。

            3)不能重載目前C++運算符集合中沒有的符號,如#,@,$等。原因有兩點,一是難以理解,二是難以確定優先級。

            4)對已經存在的運算符進行重載時,不能改變優先級規則,否則將引起混亂。

             

            函數內聯

            目的:提高執行效率。

            Q為什么要用?

            A提高執行效率。

            Q如何提高?

            A宏代碼本身不是函數,但使用起來象函數。預處理器用復制宏代碼的方式代替函數調用,省去了參數壓棧、生成匯編語言的CALL調用、返回參數、執行return等過程,從而提高了速度。

            Q缺點?

            使用宏代碼最大的缺點是容易出錯,預處理器在復制宏代碼時常常產生意想不到的邊際效應。

             

             

            例如:

            #define MAX(a, b)       (a) > (b) ? (a) : (b)

            語句

            result = MAX(i, j) + 2 ;

            將被預處理器解釋為

            result = (i) > (j) ? (i) : (j) + 2 ;

            由于運算符‘+’比運算符‘:’的優先級高,所以上述語句并不等價于期望的

            result = ( (i) > (j) ? (i) : (j) ) + 2 ;

            如果把宏代碼改寫為

            #define MAX(a, b)       ( (a) > (b) ? (a) : (b) )

            則可以解決由優先級引起的錯誤。但是即使使用修改后的宏代碼也不是萬無一失的,例如語句result = MAX(i++, j);

            將被預處理器解釋為

            result = (i++) > (j) ? (i++) : (j);

            對于C++ 而言,使用宏代碼還有另一種缺點:無法操作類的私有數據成員

            posted @ 2007-08-13 10:21 寶杉 閱讀(214) | 評論 (0)編輯 收藏

            隱藏規則:

            “隱藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下:

            1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。

            2)如果派生類的函數與基類的函數同名,并且參數也相同,但是基類函數沒有virtual關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。

             

            回顧

            靜態多態性:函數重載;運算符重載;

            動態多態性:繼承;虛函數;

             

            上述例子之所以使用指針目的是:表達一種動態性質,即當指針指向不同對象可以調用不同方法。但事實上不能達到這樣的效果。雖然可以強制指針的類型轉換((derived *p->g();),或者直接調用指向派生類的指針,但是只要將成員函數聲明為virtual就能起到這樣的作用。

            隱藏

            不同指針指向同一地址,那么指針的類型決定調用方法,還是指針指向的對象?

            例子:C++exams\hide

            可以看出,virtual函數可以實現不同類型的指針指向不同對象,調用不同的方法。

            就是說,當父類對象和子類對象同時存在,且調用父子對象的同名方法時,只能用虛擬函數實現。

             

            另外,提供一種思路:

            如果基類與派生類的同名函數參數不同,比如:

            class Base

            {

            public:

            void f(int x);

            };

            class Derived : public Base

            {

            public:

            void f(char *str);

            };

            void Test(void)

            {

            Derived *pd = new Derived;

            pd->f(10);  // error

            }

            基類為int,派生類為string.如果想在派生類中調用基類的方法,即在派生類中添加基類方法的調用。

            class Derived : public Base

            {

            public:

            void f(char *str);

            void f(int x) { Base::f(x); }

            };

            但此做法容易混亂,不宜使用。最好的方法還是用virtual

             

            指針類型

            對象類型

            面向對象動態的設計,應該是對象類型起到關鍵作用,而不是指針類型。

            posted @ 2007-08-13 10:16 寶杉 閱讀(136) | 評論 (0)編輯 收藏

            重載與覆蓋

            成員函數被重載的特征:

            1)相同的范圍(在同一個類中);

            2)函數名字相同;

            3)參數不同;

            4virtual關鍵字可有可無。

            覆蓋是指派生類函數覆蓋基類函數,特征是:

            1)不同的范圍(分別位于派生類與基類);

            2)函數名字相同;

            3)參數相同;

            4)基類函數必須有virtual關鍵字。

            例子:C++exams\cover

            指向基類的指針可以指向其共有派生類的對象,但反之不行,另外私有派生類也不行。

            比如:車 是基類,小汽車,馬車 等是派生類。

            一個車類的指針可以指向任何派生類,因為它們都屬于車。

            而反之,不能說指向馬車的指針可以指向車,因為車的概念最大。

            posted @ 2007-08-13 10:15 寶杉 閱讀(159) | 評論 (0)編輯 收藏

            重載(overloaded)、內聯(inline)、constvirtual

             

             

            重載

            內聯

            const

            virtual

            全局函數

             

             

            類的成員函數

            內部標識符

            編譯器根據參數為每個重載函數創建內部標識符,以便區分忽略返回值與有返回值的重載函數。

            連接交換指定符號

            C編譯過的函數,經過編譯器標識后與C++的表示風格不同。所以C++不能直接調用C編譯出的函數。C++提供extern “C”

            例如:

            extern “C”

            {

               void foo(int x, int y);

               … // 其它函數

            }

            或者寫成

            extern “C”

            {

               #include “myheader.h”

               … // 其它C頭文件

            }

             

            全局函數與成員函數同名

            全局函數與成員函數同名不算重載,因為函數作用域不同。

            為了區別,調用全局函數時,注意格式:

            ::函數名(參數);

             

            隱式類型轉換導致重載函數產生二義性

            隱式類型轉換:數字本身沒有類型,把數字當作參數,自動進行類型轉換。

            例如:

            void output( int x);   // 函數聲明

            void output( float x); // 函數聲明

            output(0.5)將產生編譯錯誤,因為編譯器不知道該將0.5轉換成int還是float類型的參數。

            正確寫法:

                 output(int(0.5));  // output int 0

                 output(float(0.5));    // output float 0.5

             

            posted @ 2007-08-13 10:14 寶杉 閱讀(338) | 評論 (0)編輯 收藏

            freedelete

            只是把指針所指的內存給釋放掉,但并沒有把指針本身干掉。

             

            注意:

            1)指針消亡了,并不表示它所指的內存會被自動釋放。

            2)內存被釋放了,并不表示指針會消亡或者成了NULL指針。

            比較

            mallocfree:無法滿足動態對象的要求。對象在創建同時進行構造,消亡同時析構。

            malloc free是庫函數,不是運算符,不受編譯器控制。

            newdelete:不是庫函數,能動態內存分配和清理內存。

             

            內存耗盡

            內存耗盡時newmalloc返回NULL。但在WIN32下,使用虛擬內存,不會耗盡的。

            處理內存耗盡大概有兩種。

            A  *a = new A;

            1       一處內存申請

            if(a == NULL)

            {

                 return;

                 }

            2    如果有多處申請內存,則

            if(a == NULL)

            {

                 cout << Memory Exhausted << endl;

                 exit(1);

            }

             

            newdelete使用要點

            1 new內置了sizeof、類型轉換和類型安全檢查功能。

            2 new在創建非內部數據類型的動態對象的同時完成了初始化工作。

            3 對象有多個構造函數,那么new的語句也可以有多種形式。

            例如:diary files\obj.txt

            4 如果用new創建對象數組,那么只能使用對象的無參數構造函數。例如

                 Obj  *objects = new Obj[100];    // 創建100個動態對象

            不能寫成

                 Obj  *objects = new Obj[100](1);// 創建100個動態對象的同時賦初值1

            5在用delete釋放對象數組時,留意不要丟了符號‘[]’。例如

                 delete []objects;  // 正確的用法

            delete objects;    // 錯誤的用法

            后者相當于delete objects[0],漏掉了另外99個對象。

            posted @ 2007-08-13 10:12 寶杉 閱讀(413) | 評論 (0)編輯 收藏

            數組要么在靜態存儲區被創建(如全局數組),要么在棧上被創建。數組名對應著(而不是指向)一塊內存,其地址與容量在生命期內保持不變,只有數組的內容可以改變。

            指針可以隨時指向任意類型的內存塊,它的特征是“可變”,所以我們常用指針來操作動態內存。指針遠比數組靈活,但也更危險。

            1 修改內容

                   char a[] = "hello";

                   a[0] = 'X';

                   cout << a << endl;

                   char *p = "world";     // 注意p指向常量字符串

                   p[0] = 'X';                 // 編譯器不能發現該錯誤

                   cout << p << endl;


            2 復制與比較

            strcpy(new type[strlen(a)+1]),而不能用p = a    //把a的地址給了p,而不是a的內容

            strcmp(if strcmp(a,p)== 0),而不能用      if( a = p)  

                   // 數組…

                   char a[] = "hello";

                   char b[10];

                   strcpy(b, a);                 // 不能用       b = a;

                   if(strcmp(b, a) == 0)     // 不能用  if (b == a)

                   // 指針…

                   int len = strlen(a);

                   char *p = (char *)malloc(sizeof(char)*(len+1));

                   strcpy(p,a);                  // 不要用 p = a;

                   if(strcmp(p, a) == 0)     // 不要用 if (p == a)

            sizeof內存容量計算

            1           sizeof(p)相當于sizeof(char*),C++不支持對指針所指內容容量的計算。

            char a[] = "hello world";

                char *p  = a;

                cout<< sizeof(a) << endl;   // 12字節

                cout<< sizeof(p) << endl;   // 4字節

            2           數組作為函數參數,退化成同類型指針。

            void Func(char a[100])

                {

                    cout<< sizeof(a) << endl;   // 4字節而不是100字節

            }

            指針參數傳遞內存

            首先,考慮函數為參數創建臨時副本的問題。對于值傳遞,有形參和實參的區別。但對于引用和指針傳遞,則可能會產生問題。

             

            指針作為函數參數,不能動態申請內存。

            void GetMemory(char *p, int num)

            {

                   p = (char *)malloc(sizeof(char) * num);

            }

            void Test(void)

            {

                   char *str = NULL;

                   GetMemory(str, 100);           // str 仍然為 NULL     

                   strcpy(str, "hello");               // 運行錯誤

            }

            毛病出在函數GetMemory中。編譯器總是要為函數的每個參數制作臨時副本,指針參數p的副本是 _p,編譯器使 _p = p。如果函數體內的程序修改了_p的內容,就導致參數p的內容作相應的修改。這就是指針可以用作輸出參數的原因。在本例中,_p申請了新的內存,只是把_p所指的內存地址改變了,但是p絲毫未變。所以函數GetMemory并不能輸出任何東西。事實上,每執行一次GetMemory就會泄露一塊內存,因為沒有用free釋放內存。

            如何改正:

            1 用“指向指針的指針”

            void GetMemory2(char **p, int num)          //**p

            {

                   *p = (char *)malloc(sizeof(char) * num);

            }

            void Test2(void)

            {

                   char *str = NULL;

                   GetMemory2(&str, 100);                    // 注意參數是 &str,而不是str

                   strcpy(str, "hello");

                   cout<< str << endl;

                   free(str);

            }

            2 用函數返回值來傳遞動態內存

            char *GetMemory3(int num)

            {

                   char *p = (char *)malloc(sizeof(char) * num);

                   return p;

            }

            void Test3(void)

            {

                   char *str = NULL;

                   str = GetMemory3(100);      

                   strcpy(str, "hello");

                   cout<< str << endl;

                   free(str);

            }

            注意

            強調不要用return語句返回指向“棧內存”的指針

            char *GetString(void)

            {

                   char p[] = "hello world";

                   return p;  // 編譯器將提出警告

            }

            void Test4(void)

            {

            char *str = NULL;

            str = GetString();   // str 的內容是垃圾

            cout<< str << endl;

            }

            posted @ 2007-08-03 13:08 寶杉 閱讀(199) | 評論 (0)編輯 收藏

            內存分配方式

            1 靜態存儲區域           全局變量 static

            2 棧                            局部變量

            3 動態存儲區域(堆)(malloc free) (new delete)

             

            常見錯誤和對策

            1 內存分配未成功。

            對策:程序入口處,檢查指針是否為NULL。

            (1)參數*p所指向的內存,用assert( p != NULL)

            (2)malloc或new申請的內存,用if ( p != NULL)

            2 內存未初始化。

            3 內存操作越界。

            4 忘記釋放內存,內存泄露。

            new與delete配對。

            5 釋放內存,卻繼續使用。

                   (1)return不能返回“棧內存指針”和“引用”,因為該內存在函數結束時被銷毀。

                   (2)釋放內存后,設為NULL,防止“野指針”。

            規則

            1 申請內存后檢查。assert( p != NULL)

            2 數組、動態內存初始化。

            3 申請釋放要配對。

            4 釋放內存設置NULL,防止產生野指針。

            posted @ 2007-08-03 13:06 寶杉 閱讀(185) | 評論 (0)編輯 收藏

            引用的主要作用:傳遞函數的參數和返回值。

            C++語言中,函數的參數和返回值的傳遞方式有三種:值傳遞、指針傳遞和引用傳遞。

            值傳遞

            函數內的形參是實參(外部變量)的一個拷貝,所以不會影響實參(外部變量)的值。

                void Func1(int x)

            {

                x = x + 10;

            }

            int n = 0;

                Func1(n);

                cout << “n = ” << n << endl;  // n = 0

            指針傳遞

                void Func2(int *x)

            {

                (* x) = (* x) + 10;

            }

            int n = 0;

                Func2(&n);

                cout << “n = ” << n << endl;      // n = 10

            引用傳遞

                void Func3(int &x)

            {

                x = x + 10;

            }

            int n = 0;

                Func3(n);

                cout << “n = ” << n << endl;      // n = 10

            指針功能強大,但非常危險。恰如其分的使用“引用”,發揮其作用。

            一般先考慮“引用”,如果“引用”不能做的事,則再用“指針”來完成。

            posted @ 2007-08-03 13:05 寶杉 閱讀(193) | 評論 (0)編輯 收藏

            pragma就是為了讓編譯器編譯出的C或C++程序與機器硬件和操作系統保持完全兼容而定義的宏擴展,#pragma是和特定編譯器相關的。

             

            一、Pragma說明(Directives)

            C和C++程序的每次執行都支持其所在的主機或操作系統所具有的一些獨特的特點。
            一些程序,例如,需要精確控制數據存放的內存區域或控制某個函數接收的參數。
            #pragma指示為編譯器提供了一種在不同機器和操作系統上編譯以保持C和C++完全兼容的方法。Pragmas是由機器和相關的操作系統定義的,通常對每個編譯器來說是不同的。

             

            二、語法(Syntax)

            #pragma token-string(特征字符串)特征字符串是一連串的字符,就是要給一個特定編譯器提供說明和編譯意見。

            符號(#)必須是pragma所在那一行的第一個非空格字符;
            #號和pragma之間可以有任意個空格符。
            在#pragma之后,是可以被編譯器解析的預處理特征字符。
            一般認為,#pragma屬于宏擴展。
            如果編譯器發現不認識的pragma,會提出警告,但繼續編譯下去。

            Pragmas可以用在條件聲明上,提供最新的功能性的預處理程序,或者提供給編譯器定義執行的信息。

            其格式一般為: #pragma  para 

            其中para為參數,下面來看一些常用的參數。


            alloc_text
            comment //注釋
            init_seg1 
            optimize  //最優化
            auto_inline
            component  //組成部件
            inline_depth
            pack       //包
            bss_seg
            data_seg
            inline_recursion  //內嵌遞歸
            pointers_to_members1
            check_stack
            function   
            intrinsic  //內在的
            setlocale
            code_seg
            hdrstop
            message 
            vtordisp1
            const_seg
            include_alias
            once
            warning


             

            參數詳解

            diary files\#pragma  預處理指令詳解.doc

            posted @ 2007-08-03 13:04 寶杉 閱讀(277) | 評論 (0)編輯 收藏

               * 非遞歸鎖:非遞歸鎖提供互斥的一種高效的形式,它定義一個臨界區,每一時刻只有單個線程可在其中執行。它們之所以是非遞歸的,是因為當前擁有鎖的線程在將其釋放前不可以再次獲取它。否則,就會立即發生死鎖。SunOS 5.x通過它的mutex_trwlock_t,和sema_t類型(POSIX Pthreads不提供后兩種同步機制)為非遞歸鎖提供支持。ASX構架提供MutexRW_Mutex,和Semaphore包裝,以分別封裝這些語義。

               * 遞歸鎖:另外一方面,遞歸鎖允許acquire方法嵌套調用,只要當前擁有該鎖的線程就是試圖重新獲取它的線程。遞歸鎖對于回調驅動的事件分派構架(比如1.3.2描述的反應堆)特別有用,在其中構架的事件循環執行對預登記的用戶定義的對象的回調。因為隨后用戶定義的對象可能經由它的方法入口重入分派構架,必須使用遞歸鎖以防止在回調過程中構架持有的鎖發生死鎖。

            posted @ 2007-08-03 13:03 寶杉 閱讀(3591) | 評論 (2)編輯 收藏

            僅列出標題
            共4頁: 1 2 3 4 
            国产精品99久久精品爆乳| 久久这里有精品| 漂亮人妻被黑人久久精品| 性高湖久久久久久久久AAAAA| 伊人久久综在合线亚洲2019 | 久久香蕉国产线看观看猫咪?v| 久久亚洲精品视频| 国产精品一区二区久久| 久久线看观看精品香蕉国产| 久久最近最新中文字幕大全 | 伊人久久综在合线亚洲2019| 色综合久久精品中文字幕首页| 亚洲国产精品久久久久婷婷老年| 91久久国产视频| 色综合久久久久综合99| 精品熟女少妇AV免费久久| 久久精品九九亚洲精品| 精品国产91久久久久久久| 久久99精品久久久久久噜噜| 午夜精品久久久久久| 人妻精品久久久久中文字幕一冢本| 无码人妻久久一区二区三区免费丨 | 国产免费久久精品丫丫| 亚洲国产成人精品91久久久| 国产欧美久久久精品影院| 亚洲中文精品久久久久久不卡| 国产亚洲精品美女久久久| 99久久夜色精品国产网站| 亚洲精品高清一二区久久| 奇米综合四色77777久久| 久久久久久综合一区中文字幕| 国内精品久久久久久久亚洲| 国产A级毛片久久久精品毛片| 久久97精品久久久久久久不卡| 亚洲成av人片不卡无码久久| www久久久天天com| 久久久精品久久久久影院| 99久久国语露脸精品国产| 国内精品伊人久久久久妇| 91精品观看91久久久久久| 色综合久久久久无码专区|