• <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>
            franksunny的個人技術空間
            獲得人生中的成功需要的專注與堅持不懈多過天才與機會。 ——C.W. Wendte

            symbian官方推薦使用活動服務對象(CActive)來代替多線程的使用,我想這個道理是很明了的,在手機這樣的小內存設備里,運行多線程的程序是非常耗資源的,為了節約資源,symbian提供了一個活動服務對象的框架,允許把程序里并發執行對象(其實不是并發,不過宏觀上看來是)放在一個線程里面執行,這些并發工作的對象就通過活動規劃器(ActiveScheduler)來進行管理.

            關于這兩個東西的介紹,網上有一大堆的文檔,我就不在這里廢話了,如何使用呢?這里我先舉一個簡單的計數器的例子.我選擇寫一個exe的程序,也就是說程序是以E32Main為入口的.

            GLDEF_C TInt E32Main()

            {

                CTrapCleanup* cleanup=CTrapCleanup::New();

                TRAPD(error,callInstanceL());

                if (error != KErrNone)

                {

                    printf("get error %d\r\n", error);

                }

                delete cleanup;

                return 0;

            }

            以上的內容是每一個exe文件都應該做的,CTrapCleanup* cleanup=CTrapCleanup::New()建立一個清除堆棧,以便程序在異常退出的時候把清除堆棧里面的資源都釋放掉.當然你也可以加上堆檢測宏(__UHEAP_MARK,__UHEAP_MARKEND,這里我就不多說了。TRAPDsymbian里面經常使用的宏,功能類似于try,第一個參數是讓定義一個錯誤返回值變量的名字, 后面就是可能有異常的你寫的函數.當這個函數異常時,程序不會crash, 你可以得到異常的原因.可以參考nokia論壇上的一些關于這些使用的文檔.

            接下來是vcallInstanceL函數,在這個函數里面我來建立ActiveScheduler.

            LOCAL_C void callInstanceL()

            {

                CActiveScheduler* scheduler = new(ELeave) CActiveScheduler();

                CleanupStack::PushL(scheduler);

                CActiveScheduler::Install(scheduler);

                TRAPD(error,doInstanceL());

                if(error)

                {

                    printf("error code=%d\r\n",error);

                }

                else

                {

                    printf("OK!\r\n[press any key]");

                }

                CleanupStack::PopAndDestroy(scheduler);

            }

            這段程序很簡單就是創建一個活動規劃器,并壓入清除棧,然后安裝活動規劃器,這樣就可以用了.再執行真正的實例函數,最后出棧銷毀。doinstance(該函數將在最后的代碼中給出,主要的功能就是調用我們自己寫的活動計數器)我們放到最后來寫,現在來構造我們的活動計數器對象。

            class TimeCount : public CActive

            {

            public :

                static TimeCount* NewLC(); // 構造函數

                ~TimeCount();

                void StartL();             // 計數開始

                void ConstructL();

                void RunL();             // 延時事件到達以后的處理函數

                void DoCancel();         // 取消請求提交

                void setDelayTime(int delayTime);

            private:

                TimeCount();

                RTimer iTimer;          // 定時器

                int iTimeCount;         // 計數器

                 int mTime;            // 計數間隔時間 單位秒

            };

             

            TimeCount::TimeCount():CActive(0)  // 這里可以設置活動對象的優先級

            {

                // 把自己加入活動規劃器

                CActiveScheduler::Add(this);

            }

             

            TimeCount* TimeCount::NewLC()

            {

                TimeCount* result = new (ELeave) TimeCount();

                CleanupStack::PushL( result );

                result->ConstructL();

                return result;

            }

             

            void TimeCount::DoCancel(void)

            {

                iTimer.Cancel();

            }

             

            void TimeCount::setDelayTime(int mTime)

            {

                DelayTime = mTime;

            }

             

            TimeCount::~TimeCount()

            {

                Cancel();

                iTimer.Close();

            }

             

            void TimeCount::StartL()

            {

                // 設定定時器狀態為每隔mTime秒鐘狀態完成一次

                iTimer.After(iStatus, 10000 * 100 * mTime);

                // 提交異步請求

                SetActive();

            }

             

            void TimeCount::ConstructL()

            {

                // 初始化計數器和定時器

                iTimeCount = 0;

                User::LeaveIfError(iTimer.CreateLocal());

            }

             

            void TimeCount::RunL()

            {

                // 計數器+1以后繼續提交延時請求事件

                printf("The Count is ->>%d", iTimeCount++);

                StartL();

            }

            每一個活動服務對象都有一個iStatus來標識當前對象的狀態.在這里我們把iStatus設定為iTimer.After(iStatus, 10000 * 100 * mTime);也就是定時器定時mTime秒鐘以后iStatus發生改變,這個時候活動規劃器會收到這個狀態的改變,從而調用相應活動對象的處理函數,也就是RunL函數.RunL函數里面進行計數和輸出,然后調用startL重新設置定時器和對象狀態,再提交給活動規劃器。這樣mTime秒鐘以后活動規劃器會再次調用RunL函數.一直這樣重復,這樣就達到了計數器的效果。

            最后我們來寫doinstanceL函數

            LOCAL_C void doInstanceL()

            {

                TimeCount* timeCount = TimeCount::NewLC();

                // 每隔一秒鐘打印一次

                TimeCount->setDelayTime(1);

                TimeCount->StartL();

                CActiveScheduler::Start();

                CleanupStack::PopAndDestroy(1);

            }

            創建好對象以后,加上CActiveScheduler::Start()程序就開始運行了,這句話告訴活動規劃器該等待對象的狀態的改變了(正常情況下,一旦CActiveScheduler::Start()之后,程序直到CActiveScheduler::Stop()才能終止運行),在這里就是timeCountiStatus的改變.iStatus改變并調用了RunL以后,繼續等待iStstus的改變,這樣我們使用活動對象的計數器就能夠通過消息驅動運行起來了.

            這里的CActiveScheduler只管理了一個CActive對象,就是timeCount,可以用類似的方法實現多個CActive,并且都加入CActiveScheduler,CActiveScheduler將會等待所有加入它的CActive的狀態的改變,其中有一個的狀態改變就會去執行對應的活動對象的處理函數,當狀態同時發生的時候,會通過對象的優先級來決定先調用誰的RunL函數.CActiveScheduler也是非搶占式的,當一個RunL函數還沒有執行完的時候,如果另一個CActive的狀態改變,會等待RunL執行完以后再執行另一個CActive的處理函數(正因為這一點,所以通常RunL函數不能設計為長函數,否則會阻塞活動對象)

             本文在網上根據網上用人提供的原本閱讀學習而成,可算是轉載類型的。

             

             

            posted @ 2008-10-11 21:03 frank.sunny 閱讀(2551) | 評論 (0)編輯 收藏

            Active Object (AO) 框架,是Symbian的基本工作部分。它是為了滿足多個任務同時執行的要求。在 Windows/Unix 平臺上,我們可以不加思索的使用多線程來完成多任務。可是在嵌入式平臺上,系統的資源是有限的。比如CPU、內存都比我們平時用的個人計算機要低。這就要求嵌入式系統能夠合理的使用系統資源。不能頻繁的切換線程或者進程。

            Symbian為這種特別需求設計了Active Object (AO)框架。AO框架是運行于一個線程內部的調度框架。其基本思想就是把一個單線程分為多個時間片,來運行不同的任務

            這和多線程有很大區別。多線程之間是可以被搶占的(由操作系統調度),但是AO框架中的各個任務是不可被搶占的,一個任務必須完成,才能開始下一個任務

            下面是多線程和AO框架的簡單比較:

            多線程                                       AO框架

            可以被搶占                                   不可被搶占

            上下文切換耗費CPU時間                       沒有上下文切換

            由操作系統調度                               由線程自己的AO框架調度

            每個線程都有至少4K Stack.                    AO沒有單獨的Stack.

            操作系統還要分配額外的資源記錄線程            只是一個Active Object.

            Symbian系統本身使用了大量的AO框架來實現一些系統服務。這使得Symbian和其他嵌入式系統相比較,對系統資源的使用更加合理。

            AO框架包括CActiveScheduler CActive (Active Object)。一個線程的所有的Active Object對象都被安裝在該線程的CActiveScheduler對象內.CActiveScheduler對象監控每個Active Object是否完成了當前任務,如果完成了,就調度下一個Active Object來執行。CActiveScheduler根據優先級來調度各個Active Object.

             

            關于CActiveScheduler的創建和安裝,CActive的創建和安裝,和CActive的任務處理,可以參看 SDK 文檔。理解起來不難。下面要說一個比較容易忽略的地方。這對理解AO框架非常重要。

            創建調度器:

            CActiveScheduler * scheduler = new (ELeave) CActiveScheduler;

            CleanupStack::PushL(scheduler);

            CActiveScheduler::Install(scheduler);

             

            運行調度器:

            CActiveScheduler::Start();

             

            停止調度器:

            CActiveScheduler::Stop();

             

            以上代碼都是運行在一個線程中的,一般來講,一個EXE只有一個主線程.

            可是如果真的有2個線程呢?

            為什么在當前線程下調用CActiveScheduler::Start(),CActiveScheduler::Stop()運行/停止的就是當前線程的調度器而不是另一個線程的調度器?

            每個線程都有自己的CActiveScheduler,那么這個CActiveScheduler類是怎么調用CActiveScheduler::Start(),CActiveScheduler::Stop()來運行/停止當前的調度器的呢?

            我們看到Start/Stop并沒有參數.

            打開CActiveScheduler的類定義:

            class CActiveScheduler : public CBase

                {

            public:

                IMPORT_C CActiveScheduler();

                IMPORT_C ~CActiveScheduler();

                IMPORT_C static void Install(CActiveScheduler* aScheduler);

                IMPORT_C static CActiveScheduler* Current();

                IMPORT_C static void Add(CActive* anActive);

                IMPORT_C static void Start();

                IMPORT_C static void Stop();

                IMPORT_C static TBool RunIfReady(TInt& aError, TInt aMinimumPriority);

                IMPORT_C static CActiveScheduler* Replace(CActiveScheduler* aNewActiveScheduler);

                IMPORT_C virtual void WaitForAnyRequest();

                IMPORT_C virtual void Error(TInt anError) const;

            private:

                void DoStart();

                void OwnedStartLoop(TInt& aRunning);

                IMPORT_C virtual void OnStarting();

                IMPORT_C virtual void OnStopping();

                IMPORT_C virtual void Reserved_1();

                IMPORT_C virtual void Reserved_2();

            private:

                // private interface used through by CActiveSchedulerWait objects

                friend class CActiveSchedulerWait;

                static void OwnedStart(CActiveSchedulerWait& aOwner);

            protected:

                inline TInt Level() const;

            private:

                TInt iLevel;

                TPriQue<CActive> iActiveQ;

                };

             

            我們并沒有看到靜態的成員來表示線程,但是卻有一個static函數CActiveScheduler* Current();返回當前線程的調度器.

            現在猜想奧秘就在這個函數是怎么實現的。這個靜態的函數怎么就能得到當前這個運行線程的調度器,而不是別的線程的調度器。我們可以猜想,肯定是Current()內部實現能取到當前線程的標識信息.用這個標識,靜態函數能取到這個線程的CActiveScheduler.這個具體如何實現呢?

            答案就是:當前線程的線程ID可以這樣得到:

            創建一個缺省的線程對象:

            RThread thread;

            取得當前線程的ID:

            TThreadId threadId = thread.Id();

            能得到當前線程的threadId,當然可以得到和當前線程關聯的CActiveScheduler。因此以上兩個問題也就迎刃而解了,在一個線程內調用CActiveScheduler::Start(),CActiveScheduler::Stop()開啟的就是當前線程。

            既然回復了上面的問題,那么我們自然就能明確,在一個線程內是不能通過StartStop函數來開啟和停止另一個線程內的活動對象規劃器CActiveScheduler

             

            補充點其他東西:

            Symbian操作系統中,每個進程都有一個或多個線程。線程是執行的基本單位。一個進程的主線程是在進程啟動時生成的。Symbian屬于搶占式多任務操作系統,這意味著每個線程都有自己的執行時間,直到系統將CPU使用權給予其他線程。當系統調度時,具有最高優先權的線程將首先獲得執行。

            進程邊界是受內存保護的。所有的用戶進程都有自己的內存地址空間,同一進程中的所有線程共享這一空間,用戶進程不能直接訪問其他進程的地址空間。

            每個線程都有它自己的stackheap,這里heap可以是私有的,也可以被其他線程共享。應用程序框架生成并安裝了一個active scheduler,并且為主線程準備了清除棧。如果沒有使用框架(如編寫exe程序)那就要手動生成這些了。

            Symbian操作系統專為單線程應用優化,因此強烈推薦使用“活動對象”代替多線程。

            posted @ 2008-10-11 20:34 frank.sunny 閱讀(2679) | 評論 (2)編輯 收藏

             

            如何在C++中調用C的代碼

             

            以前曾經總結過一篇(http://www.shnenglu.com/franksunny/archive/2007/11/29/37510.html),關于在C中如何調用C++的代碼,當時并未做完全的展開,只是簡單的做了下調試,最近看到一個題目要求實現CC++中代碼的互相調用,其結果雖然都是通過extern “C”來實現,但是具體還是有些差別的。

            先對C中調用C++代碼作個簡單回顧:

            1、              對于C++中非類的成員函數,可以簡單的在函數聲明前面加extern “C”,通常函數聲明位于頭文件中,當然也可以將聲明和函數定義一起放在cpp,在沒有聲明的情況下,直接在定義前添加extern “C”也可

            2、              對于C++類的成員函數,則需要另外做一個cpp文件,將需要調用的函數進行包裝

            以上兩項的實例參看前面C中如何調用C++代碼的文章。

            要實現C++中調用C的代碼,具體操作:

            對于C中的函數代碼,要么C代碼的頭文件進行修改,在其被含入C++代碼時在聲明中加入extern “C”或者C++代碼中重新聲明一下C函數,重新聲明時添加上extern “C”

            通過以上的說明,我明白一點,那就是extern “C”頭一定是加在C++的代碼文件中才能起作用的

             

            下面分析一下這個現象的實質原因:

            C編譯器編譯函數時不帶函數的類型信息,只包含函數符號名字,如C編譯器把函數int a(float x)編譯成類似_a這樣的符號,C連接器只要找到了調用函數的符號,就可以連接成功,它假設參數類型信息是正確的,這是C編譯連接器的缺點。而C++編譯器為了實現函數重載,編譯時會帶上函數的類型信息,如他把上面的a函數可能編譯成_a_float這樣的符號為了實現重載,注意它還是沒有帶返回值得信息,這也是為什么C++不支持采用函數返回值來區別函數重載的原因之一,當然,函數的使用者對函數返回值的處理方式(如忽略)也是重要原因。

            基于以上,C調用C++,首先需要用封裝函數把對C++的類等的調用封裝成C函數以便C調用,于是extern "C"的作用是:讓編譯器知道這件事,然后C語言的方式編譯和連接封裝函數通常是把封裝函數用C++編譯器按C++方式編譯,用了extern "C" 后,編譯器便依C的方式編譯封裝接口,當然接口函數里面的C++語法還是按C++方式編譯;對于C語言部分--調用者,還是按C語言編譯;分別對C++接口部分和C部分編譯后,再連接就可以實現C調用C++)。相反,C++調用C函數,extern "C" 的作用是:讓C++連接器找調用函數的符號時采用C的方式,即使用_a而不是_a_float來找調用函數。

             

            具體示例請見http://www.shnenglu.com/Files/franksunny/CCallCpp.rar

            注:如果你用VC6.0編譯附件時遇到類似“fatal error C1010: unexpected end of file while looking for precompiled header directive”報錯的話,請將bb.c文件做如下處理右鍵點擊項目工程中的該文件,選擇setting,在c/c++欄,選擇PreCompiled headers,然后設置第一選項,選擇不使用預編譯頭。

             

            posted @ 2008-10-10 17:54 frank.sunny 閱讀(8977) | 評論 (1)編輯 收藏
                 摘要:   活動對象框架原理   一、概述: Symbian OS是一個多任務的操作系統,那么為了實現多任務,同時使系統能夠快速響應,高效的進行事件處理,并減輕應用程序員的工作負擔(申請大多數耗時的操作(例如文件系統)由服務提供器來完成,服務提供器完成程序員提交的請求后,將會返回給程序員一個成功或失敗的信號。),Symbian OS特意引入了活動對象的概念。 服務提供器API...  閱讀全文
            posted @ 2008-10-09 20:42 frank.sunny 閱讀(1809) | 評論 (0)編輯 收藏

            這種在Symbian C/S架構中,服務器程序與客戶UI進程主動通信中用的比較多。

            對于在往UI框架應用程序發送消息,可以通過Symbian OSApplication Architecture Services可以進行應用程序間的通信,主要用到的類包括:TApaTaskListTApaTask

            TApaTaskList:用于訪問設備中正在運行的任務(假如有些任務隱藏了的話,那么通過這種方法也無法進行訪問)。

            TApaTask:表示設備中某個運行的任務,通過與程序關聯的窗口組(window group)標識。

            具體的解決方案:

            發送消息端:使用TApaTaskList找到等待接收消息的任務,TApaTaskList::FindApp()提供了兩個重載版本,可以使用程序的標題,也可以使用程序的UID進行查找。獲得需要發消息的任務后就可以通過TApaTask:: SendMessage()發送消息了,它有兩個參數,第一個參數用于標識消息,第二個參數是一個描述符的引用,可以用來提供不同消息時附加的具體信息。

            TUid uid( TUid::Uid( 0x0116C9D3 ) );

            TApaTaskList taskList( iCoeEnv->WsSession() );

            TApaTask task = taskList.FindApp(uid );

             

            if( task.Exists() ) //判斷任務是否正在運行

            {

                LIT8( KTestMsg, "CustomMessage" );

                TUid msgUid( TUid::Uid( 1 ) );

                task.SendMessage( uid, KTestMsg );

            }

             

            接收消息端可以使用如下兩種方案:

            第一種方案:由于MCoeMessageObserver是處理來自窗口服務器消息的接口類,而CEikAppUi已經繼承自MCoeMessageObserver,所以我們只需要在自己的UI類中重現實現MCoeMessageObserver的唯一成員函數HandleMessageL()用來處理接收到的消息即可,代碼如下:

            MCoeMessageObserver::TMessageResponse CXXXAppUi::HandleMessageL(TUint32 aClientHandleOfTargetWindowGroup, TUid aMessageUid, const TDesC8& aMessageParameters)

            {

                _LIT( KFormatStr, "%x" );

                TBuf<32> bufUid;

                TBuf<32> bufPara;

                bufUid.AppendFormat( KFormatStr, aMessageUid.iUid );

                bufPara.Copy( aMessageParameters );

                iEikonEnv->InfoWinL( bufUid, bufPara );

                return MCoeMessageObserver::EMessageHandled;

            }

             

            第二種方案:由于TApaTask::SendMessage()發送的消息可以被CEikAppUI的成員函數ProcessMessageL()攔截并處理,不過必須在沒有重載HandleMessageL()函數的前提下,而且函數ProcessMessageL()只負責攔截消息標識為KUidApaMessageSwitchOpenFileValueKUidApaMessageSwitchCreateFileValue的這兩個消息,其它標識值的消息不會被傳到ProcessMessageL()中,所以這種方案個人覺得很受限制,不自由,還是采用第一種方案好,具體代碼代碼如下:

            //發送:

            TUid uid( TUid::Uid( 0x0116C9D3 ) );

            TApaTaskList taskList( iCoeEnv->WsSession() );

            TApaTask task = taskList.FindApp(uid );

             

            if( task.Exists() ) //判斷任務是否正在運行

            {

                LIT8( KTestMsg, "CustomMessage" );

                //這里的Uid不能使用自定義的,而且只有系統提供的兩個

                TUid msgUid( TUid::Uid(KUidApaMessageSwitchCreateFileValue) );

                task.SendMessage( uid, KTestMsg );

            }

             

            //接收:

            void CXXXAppUi::ProcessMessageL(TUid aUid,const TDesC8& aParams)

            {

                RFileLogger iLog;

                iLog.Connect();

                iLog.CreateLog(_L("tb"), _L("UpdateListener2.txt"), EFileLoggingModeOverwrite);

                iLog.Write(_L("smms appui"));

             

                if (aUid.iUid == KUidApaMessageSwitchCreateFileValue)

                {

                    TBuf<256> buf;

                    buf.Copy(aParams);

                    iLog.Write(aParams);

                    BringMeToFront();

                    ShowCreateFile(buf,CFileMonitorEngine::EImageType);

                }

                else

                {

                    CAknViewAppUi::ProcessMessageL(aUid,aParams);

                }

                iLog.Close();

            }


            明天就是中秋了,恭祝大家中秋節快樂
            posted @ 2008-09-13 07:46 frank.sunny 閱讀(2065) | 評論 (1)編輯 收藏
                 摘要:   關于vCard和Symbian上的操作   前陣子關于Symbian通訊錄操作的時候曾提到vCard,但是由于當時項目比較緊,所以也沒有時間整理,今天特意抽了點時間小試了一下,發現很多手機(我試了下索愛的和諾基亞的)如果選中通訊錄中的記錄發送聯系人或者發送名片之類的操作,就是會以vcf文件格式進行發送。不過手機上的vcf文件通常是用UTF-8編碼的,所以雖然可以用ou...  閱讀全文
            posted @ 2008-09-13 07:20 frank.sunny 閱讀(3691) | 評論 (0)編輯 收藏
                 摘要: Symbian OS平臺簡體漢字編程編碼處理   相信大家都在處理symbian中文顯示的時候遇到了編碼的問題,我現在就給總結一下這種問題的解決方法: 字符串編碼中文表示常用的有:GB2312,GBK,Unicode,UTF-8 其中GBK是GB2312的超集,也就是涵蓋了GB2312編碼的所有內容; UTF-8是Unicode的在網絡傳輸中的一種編碼格式。 如果我們使用...  閱讀全文
            posted @ 2008-09-10 20:11 frank.sunny 閱讀(4094) | 評論 (1)編輯 收藏
                 摘要: Symbian OS中的消息存儲與常用操作 說明:本文前面消息的基本知識主要參考《Series60應用程序開發》中的有關內容,后面是前段做MTM開發中用到的代碼。 一、消息存儲基本知識 Symbian OS提供的消息傳送架構基于Client/Server機制,服務器負責管理手機上的各種消息,在進行消息相關操作之前我們需要了解Symbian OS是如何組織和存儲消息的。 手機中的各種消息...  閱讀全文
            posted @ 2008-07-30 21:04 frank.sunny 閱讀(3244) | 評論 (2)編輯 收藏
                 摘要:   Symbian OS應用開發學習筆記之通訊錄(電話薄Contacts)   Symbian OS通訊錄模型 Symbian OS手機的通訊錄采用文件方式存儲,用symbian自己的說法就是通訊錄數據庫。每個Symbian OS手機都有一個默認的通訊錄數據庫,這個通訊錄數據庫在2nd和3rd兩個版本手機中的位置是不同的,前者是c:\ system\data\Conta...  閱讀全文
            posted @ 2008-06-27 08:05 frank.sunny 閱讀(6421) | 評論 (8)編輯 收藏

             

            今天接到電話面試,被問到幾個問題,汗顏之余,小結一下

            1、      多態是如何實現綁定的

            多態的綁定可以分為運行是多態和編譯時多態

            編譯時的多態性

            編譯時的多態性是通過重載來實現的。對于非虛的成員來說,系統在編譯時,根據傳遞的參數、返回的類型等信息決定實現何種操作。

            運行時的多態性

            運行時的多態性就是指直到系統運行時,才根據實際情況決定實現何種操作。C#中,運行時的多態性通過虛成員實現。

            編譯時的多態性為我們提供了運行速度快的特點,而運行時的多態性則帶來了高度靈活和抽象的特點。

            今天才正式弄清楚原來虛函數是可以實現運行時多態的,以前只知道虛函數可以使得基類對象的的方法調用派生類的方法。

            2、      析構函數是虛函數的優點是什么

            C++開發的時候,用來做基類的類的析構函數一般都是虛函數。可是,為什么要這樣做呢?下面用一個小例子來說明:

            有下面的兩個類:

            class ClxBase

            {

            public:

                ClxBase() {};

                virtual ~ClxBase() {};

             

                virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };

            };

             

            class ClxDerived : public ClxBase

            {

            public:

                ClxDerived() {};

                ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };

             

                void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };

            };

             

            代碼

             

            ClxBase *pTest = new ClxDerived;

            pTest->DoSomething();

            delete pTest;

             

            輸出結果是:

             

            Do something in class ClxDerived!

            Output from the destructor of class ClxDerived!

             

            這個很簡單,非常好理解。

            但是,如果把類ClxBase析構函數前的virtual去掉,那輸出結果就是下面的樣子了:

            Do something in class ClxDerived!

            也就是說,類ClxDerived的析構函數根本沒有被調用!一般情況下類的析構函數里面都是釋放內存資源,而析構函數不被調用的話就會造成內存泄漏。我想所有的C++程序員都知道這樣的危險性。當然,如果在析構函數中做了其他工作的話,那你的所有努力也都是白費力氣。

            所以,文章開頭的那個問題的答案就是--這樣做是為了當用一個基類的指針刪除一個派生類的對象時,派生類的析構函數會被調用。

            當然,并不是要把所有類的析構函數都寫成虛函數。因為當類里面有虛函數的時候,編譯器會給類添加一個虛函數表,里面來存放虛函數指針,這樣就會增加類的存儲空間。所以,只有當一個類被用來作為基類的時候,才把析構函數寫成虛函數。

             

            說實話,這個也是今天才深刻認識到的。

             

            當然還問到很多數據結構和算法方面(空間復雜度和時間復雜度之類的東東,說真的也是基礎性的)的問題,至于那些東西,自己說實話拋開沒用他們已經很長時間了,真可以說忘的差不多了,考這種真的很怕,也怪平時沒怎么用到。不知道大家用的多不?

            好久沒有正式參加過面試了,今天突然來一次覺得自己基礎還是不夠扎實。

            posted @ 2008-05-19 20:30 frank.sunny 閱讀(18122) | 評論 (12)編輯 收藏
            僅列出標題
            共7頁: 1 2 3 4 5 6 7 

            常用鏈接

            留言簿(13)

            隨筆分類

            個人其它博客

            基礎知識鏈接

            最新評論

            閱讀排行榜

            評論排行榜

            2022年国产精品久久久久| 日本久久久久亚洲中字幕| www久久久天天com| 99久久99久久精品国产片果冻| 久久精品国产秦先生| 久久久久亚洲AV无码去区首| 久久夜色撩人精品国产小说| 国产99久久久国产精品小说| 久久国产精品无码HDAV| 亚洲一区中文字幕久久| 国内精品人妻无码久久久影院导航 | 99久久www免费人成精品| 国产午夜精品理论片久久| 99精品久久精品一区二区| 一级做a爱片久久毛片| 国产成人精品综合久久久| 亚洲成色999久久网站| 超级97碰碰碰碰久久久久最新 | 久久久久无码中| 97久久精品无码一区二区| 久久只这里是精品66| 精品久久久久久久久久久久久久久| 18岁日韩内射颜射午夜久久成人 | 久久影院综合精品| 久久人人爽人人爽人人爽| 久久激情五月丁香伊人| 99精品久久精品一区二区| 麻豆av久久av盛宴av| 欧美一级久久久久久久大| 88久久精品无码一区二区毛片 | 国产精品国色综合久久| 日本人妻丰满熟妇久久久久久| 国产99久久久国产精品小说| 看全色黄大色大片免费久久久| 国产精品久久久天天影视香蕉| 中文字幕一区二区三区久久网站| 日本久久久久亚洲中字幕| 色欲综合久久中文字幕网| 久久精品国产清自在天天线| 国产香蕉久久精品综合网| 久久综合久久鬼色|