• <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>

            Beginning to 編程

            VC++ 方面編程文章

             

            2006年7月16日

            Windows GDI CDC 使用問題

            最近在學(xué)習(xí)Hoops?? 的引擎(http://www.hoops3d.com )

            模擬它的MVO架構(gòu),不過沒有原代碼,所以很難a
            設(shè)計了一個交互繪圖基本類,
            但是還有錯誤,鼠標(biāo)左鍵點擊兩下
            ?winGDI.cpp中出錯。
            請大蝦指教一二。
            我已經(jīng)在這個問題上花了很多的心思。
            其中最重要的就是Painter抽象類的設(shè)計
            他的子類QBufferDC繼承CDC
            而SGView包含Painter指針,方便在SGView ::drawEntity調(diào)用。



            SGObject - 對象的抽象類,也就是幾何對象
            SGModel- 負(fù)責(zé)對象管理,沒有實現(xiàn)所有的功能,準(zhǔn)備用SceneTree來實現(xiàn)
            SGView - 負(fù)責(zé)顯示SGModel中的數(shù)據(jù),關(guān)鍵的函數(shù)
            void SGView::drawEntity(SGObject* pObj)
            {
            ???pObj->draw(m_pPainter,this)
            }

            Painter - 封裝CDC的功能,見代碼

            在CSGView創(chuàng)建的時候創(chuàng)建Painter對象
            很可能這里有問題!!!!!
            void CSGView::OnCreate(..)
            {
            ?????CDC*?pDC =?GetDC();
            ???Painter* painter = new QBufferDC(pDC);
            ???m_pSGView->setPainter(painter);
            }


            MFC 相關(guān)的Document/View架構(gòu)
            CSGDocument - 管理SGModel

            CSGView - 和SGView建立聯(lián)系,并負(fù)責(zé)把windows的消息發(fā)送給SGView
            見原代碼

            SGActionManager - 負(fù)責(zé)工具的管理
            SGBaseAction - 工具的抽象基類
            SGActionDrawLine - 繪制直線的工具



            源代碼連接:
            http://www.shnenglu.com/Files/richardzeng/MVOTest.rar

            posted @ 2006-07-16 03:06 Beginning to 編程 閱讀(1446) | 評論 (2)編輯 收藏

            2006年5月27日

            資源和資源管理類的設(shè)計問題


            我要設(shè)計的應(yīng)用程序其中的一個模塊就是封裝 windows GDI中的畫筆,畫刷等GDI object
            把GDI object 再封裝成resource,以實現(xiàn)多種樣式多線條的畫筆及畫刷資源

            畫筆,畫刷等資源繼承resource
            為了避免發(fā)生資源泄露和resource的管理
            設(shè)計ResourceManager類,負(fù)責(zé)資源的創(chuàng)建,加載和卸載以及刪除

            兩個抽象類 Resource 和 ResourceManager
            兩個具體類 ConcreateResource 和 ConcreateResourceManager
            分別派生于上面的抽象類

            以上設(shè)計是看了 OGRE 游戲引擎的資源管理部分,
            對它的資源管理類ResourceManager不是很理解

            resource 派生了pen,brush等類
            pen類可以來自文件,也可以自己創(chuàng)建SubPen 添加到SubPenList中

            ResourceManager 負(fù)責(zé)創(chuàng)建資源Resource
            1. 如果我在抽象的 ResourceManager 聲明 createRes函數(shù),并返回基類resource
            勢必會要強制轉(zhuǎn)換,然后在用到具體的Resource時候又要轉(zhuǎn)換回來

            2. 如果我在具體類 ConcreateResourceManager 聲明 createConcreateRes函數(shù)
            那么就白費了我應(yīng)用設(shè)計模式設(shè)計這么多類


            // abstract class for resource
            class Resource{
            public:
            ?// standard constructor
            ? Resource(const string& name, const string& group)
            ?:mName(name),mGroup(group){}
            ? ~Resource(){}
            protected:
            ?// prevent default construct
            ? Resource():mName(""),mGroup(""){}
            ? string mName;
            ? string mGroup;
            ? static unsigned long mHandle;
            };

            // subclass of resource
            // concreateResource such as PEN
            class Pen:
            ?public Resource{
            ?Pen(const string& name, const string& group)
            ??:Resource(name,group){}
            ??~Pen(){}

            ? void loadfromFile(string& filename);

            // add?into vector
            ? void addSubPen(SubPen* sub){
            ???? mSubPenList.push_back(sub);
            }
            public:
            typedef std::vector<SubPen> SubPenList;
            SubPenList mSubPenList;

            };
            class
            // abstract class for resource manager
            class ResourceManager{
            public:
            ? ResourceManager(){}
            ? ~ResourceManager(){}
            public:
            // here , I cannot understand OGRE degsin
            ? Resource* createRes(const string& name,const string& group);
            ?// resource map
             typedef std::map<string,Resource*> ResourceMap;
            ?? ResourceMap mResources;

            };

            // subclass ResourceManager
            class ConcreateResourceManager
            ?:public ResourceManager
            {
            ?ConcreateResourceManager(){}
            ?~ConcreateResourceManager(){}

            ????? // how can design here!!
            ?????? Pen* createPen(const string& name,const string& group){}
            }

            ?

            posted @ 2006-05-27 22:19 Beginning to 編程 閱讀(706) | 評論 (1)編輯 收藏

            2006年5月15日

            MFC 容器類對象的序列化問題

            設(shè)計一個程序?qū)崿F(xiàn)如何保存一系列的SPen(如下定義)對象到文件,或者稱為序列化SPen collection

            SPenCollection::Load和 Save函數(shù)實現(xiàn)打開畫筆文件(文件的內(nèi)容是一系列SPen對象)
            // for example
            ?SPenCollection pc;
            ?pc.Load("C:\\1.pen");

            我不知道如何序列化容器類對象,請大蝦指教。



            // SPen object
            class SPen : public CObject
            {
            ?DECLARE_SERIAL(SPen)
            public:
            ?SPen();
            ?virtual ~SPen();

            public:
            ?int lineStyle;
            ?int lineWidth;
            ?COLORREF lineColor;
            public:
            ?virtual void Serialize(CArchive& ar);
            };


            // SPen.cpp : 實現(xiàn)文件
            //

            #include "stdafx.h"
            #include "ArchiveTest.h"
            #include "SPen.h"


            // SPen
            IMPLEMENT_SERIAL(SPen,CObject,1)

            SPen::SPen()
            {
            ?lineStyle = PS_SOLID;
            ?lineWidth = 2;
            ?lineColor = RGB(255,0,0);
            }

            SPen::~SPen()
            {
            }


            // SPen 成員函數(shù)

            void SPen::Serialize(CArchive& ar)
            {
            ?if (ar.IsStoring())
            ?{?// storing code
            ??ar<<lineStyle;
            ??ar<<lineWidth;
            ??ar<<lineColor;
            ?}
            ?else
            ?{?// loading code
            ??ar>>lineStyle;
            ??ar>>lineWidth;
            ??ar>>lineColor;
            ?}
            }


            ///////////////////////////////////////
            // 關(guān)鍵是要實現(xiàn)如何保存一系列的SPen對象
            // load 和 save函數(shù)實現(xiàn)打開畫筆文件(文件的內(nèi)容是一系列SPen對象)
            // for example
            /** SPenCollection pc;
            ???pc.Load("C:\\1.pen");
            ?**/

            #pragma once

            // SPenCollection 命令目標(biāo)

            #include "SPen.h"
            #include <afxtempl.h>

            class SPenCollection : public CObject
            {
            ?DECLARE_SERIAL(SPenCollection)
            public:
            ?SPenCollection();
            ?virtual ~SPenCollection();

            ?void AddPen(SPen* pen);

            ?void Load(CString strFileName);
            ?void Save(CString strFileName);

            // CArray 不知道用得對不對,請大蝦指教
            ?CArray<SPen*,SPen*> pens;
            };


            ?

            posted @ 2006-05-15 22:14 Beginning to 編程 閱讀(1399) | 評論 (1)編輯 收藏

            boost serialize 和 ostream 問題

            下面是Boost serialization 中的demo例子
            為何寫了serialize 函數(shù)還寫個ostream<<
            阿,
            我對ostream 不是很了解,
            我的印象是iostream 是在控制臺里輸入輸出的
            /////////////////////////////////////////////////////////////////////////////
            class gps_position
            {
            ??? friend std::ostream & operator<<(std::ostream &os, const gps_position &gp);
            ??? friend class boost::serialization::access;
            ??? int degrees;
            ??? int minutes;
            ??? float seconds;
            ??? template<class Archive>
            ??? void serialize(Archive & ar, const unsigned int /* file_version */){
            ??????? ar & degrees & minutes & seconds;
            ??? }
            public:
            ??? // every serializable class needs a constructor
            ??? gps_position(){};
            ??? gps_position(int _d, int _m, float _s) :
            ??????? degrees(_d), minutes(_m), seconds(_s)
            ??? {}
            };
            std::ostream & operator<<(std::ostream &os, const gps_position &gp)
            {
            ??? return os << ' ' << gp.degrees << (unsigned char)186 << gp.minutes << '\'' << gp.seconds << '"';
            }

            posted @ 2006-05-15 17:26 Beginning to 編程 閱讀(847) | 評論 (1)編輯 收藏

            fatal error LNK1104: 無法打開文件“l(fā)ibboost_serialization-vc80-mt-gd-1_33_1.lib”

            ?最近想試試boost,下載了boost 1.33.1
            我目前使用的是VC++2005,
            首先編譯bjam, 不過用boost 1.33.1 \tools \jam-src 下的build.bat不用又從sf上下載了
            最新的bjam,然后編譯bjam,倒是很簡單很快就好生成bjam.exe

            然后把bjam的路徑設(shè)置到path 環(huán)境變量中
            一切都運行正常。

            我首先就編譯了boost -serialization

            在命令行模式下
            cd <boost-serialization 目錄>
            運行bjam "-sTOOLS=vc-8_0"

            編譯完成后在boost 目錄下生成了bin 目錄C:\boost_1_33_1\bin\
            我編譯的serialization lib 文件在這里
            C:\boost_1_33_1\bin\boost\libs\serialization\build\boost_serialization.dll\vc-8_0\debug\threading-multi,當(dāng)然還有其它的lib,dll

            首先設(shè)置vc++包含文件目錄C:\boost_1_33_1\
            庫文件設(shè)置在C:\boost_1_33_1\bin\boost\libs\serialization\build\boost_serialization.dll\vc-8_0\debug\threading-multi,
            (這個肯定不好,難道我需要一個lib文件就要在這里加一個路徑,因為編譯的lib文件太分散,沒有集中,不知道copy到一起是否可行)

            然后我copy boost serialization 中demo代碼,
            編譯demo.cpp,就提示 fatal error LNK1104: 無法打開文件“l(fā)ibboost_serialization-vc80-mt-gd-1_33_1.lib”

            我想是不是lib文件的路徑不對阿,把要的libboost_serialization-vc80-mt-gd-1_33_1.lib 拷貝到C:\boost_1_33_1\libs
            下還是不行,設(shè)置項目依賴文件也不行,
            到底在vc++2005 中怎么設(shè)置boost的環(huán)境阿

            posted @ 2006-05-15 10:54 Beginning to 編程 閱讀(10606) | 評論 (6)編輯 收藏

            2006年5月10日

            不能將“this”指針從“const Vector3D”轉(zhuǎn)換為“Vector3D &" 錯誤

            我在VS2005中編譯Vector3D類出現(xiàn)
            error C2662: “Vector3D::dotP”: 不能將“this”指針從“const Vector3D”轉(zhuǎn)換為“Vector3D &”

            怎么樣改正呢,這個類也是看到別人這樣寫的,編譯也沒有錯誤。

            #pragma once

            #define M_PI 3.141
            #include <math.h>

            class Vector3D{
            ?Vector3D(){x=y=z=0.0;}
            ?Vector3D(double vx, double vy,double vz=0.0){
            ??x = vx;
            ??y = vy;
            ??z = vz;
            ?}
            ?
            ?double magnitude() const{
            ??return sqrt(x*x+y*y+z*z);
            ?}

            ?double dotP(const Vector3D& v1,const Vector3D& v2){
            ??return (v1.x*v2.x+v1.y*v2.y+v1.z*v2.z);
            ?}

            ?// get the vector angle
            ?double angle() const{
            ??double ret = 0.0;
            ??double m = magnitude();

            ??if (m>1.0e-6) {

            //?問題出在這里!!!!
            // ==============================
            ???double dp = dotP(*this,Vector3D(1.0,0.0));
            //==============================

            ???if (dp/m>=1.0) {
            ????ret = 0.0;
            ???}
            ???else if (dp/m<-1.0) {
            ????ret = M_PI;
            ???}
            ???else {
            ????ret = acos( dp / m);
            ???}
            ???if (y<0.0) {
            ????ret = 2*M_PI - ret;
            ???}
            ??}
            ??return ret;
            ?}


            protected:
            ?double x;
            ?double y;
            ?double z;

            };#pragma once

            #define M_PI 3.141
            #include <math.h>

            class Vector3D{
            ?Vector3D(){x=y=z=0.0;}
            ?Vector3D(double vx, double vy,double vz=0.0){
            ??x = vx;
            ??y = vy;
            ??z = vz;
            ?}
            ?
            ?double magnitude() const{
            ??return sqrt(x*x+y*y+z*z);
            ?}

            ?double dotP(const Vector3D& v1,const Vector3D& v2){
            ??return (v1.x*v2.x+v1.y*v2.y+v1.z*v2.z);
            ?}

            ?// get the vector angle
            ?double angle() const{
            ??double ret = 0.0;
            ??double m = magnitude();

            ??if (m>1.0e-6) {
            ???double dp = dotP(*this,Vector3D(1.0,0.0));

            ???if (dp/m>=1.0) {
            ????ret = 0.0;
            ???}
            ???else if (dp/m<-1.0) {
            ????ret = M_PI;
            ???}
            ???else {
            ????ret = acos( dp / m);
            ???}
            ???if (y<0.0) {
            ????ret = 2*M_PI - ret;
            ???}
            ??}
            ??return ret;
            ?}


            protected:
            ?double x;
            ?double y;
            ?double z;

            };

            posted @ 2006-05-10 14:42 Beginning to 編程 閱讀(6436) | 評論 (2)編輯 收藏

            2006年4月21日

            C++中Singleton的實現(xiàn)[zhuan]


            這些東西在網(wǎng)上都很多了,但是我覺得他們的使用都不符合我的要求,所以自己動手豐衣足食,寫一個自己能用的,夠用就好。
            #include <iostream>
            ?
            using namespace std;
            ?
            //單件模板類
            template<typename T> class Singleton
            {
            protected:
            ?
            ? static T* m_Instance;
            ?
            ? Singleton(){}
            ? virtual~Singleton(){}
            ?
            public:
            ?
            ? //實例的獲得
            ? static T* Instance()
            ? {
            ??? if(m_Instance==0)
            ????? m_Instance=new T;
            ?
            ??? return m_Instance;
            ? }
            ?
            ? //單件類的釋放
            ? virtual void Release()
            ? {
            ??? if(m_Instance!=0)
            ??? {
            ????? delete m_Instance;
            ????? m_Instance=0;
            ??? }
            ? }
            };
            ?
            //單件模板測試類
            class Test:public Singleton<Test>
            {
            ? friend class Singleton<Test>; //聲明為友員,不然會出錯
            protected:
            ? Test()
            ? {
            ??? a=b=c=0;
            ? }
            ? virtual ~Test(){}
            ?
            public :
            ?
            ? int a;
            ? int b;
            ? int c;
            };
            ?
            //初始化靜態(tài)成員。。。
            template<> Test*Singleton<Test>::m_Instance=0;
            ?
            ?
            //以下為測試代碼
            void main()
            {
            ? Test*t=Test::Instance();
            ?
            ? t->a=5;
            ? t->b=25;
            ? t->c=35;
            ? cout<<"t: a="<<t->a<<" b="<<t->b<<" c="<<t->c<<endl;
            ?
            ? Test*t2;
            ? t2=Test::Instance();
            ? cout<<"t2 a="<<t2->a<<" b="<<t2->b<<" c="<<t2->c<<endl;
            ?
            ? t2->Release();
            }

            posted @ 2006-04-21 09:31 Beginning to 編程 閱讀(367) | 評論 (0)編輯 收藏

            2006年3月24日

            EffectiveC++2ed 關(guān)于函數(shù)返回對象,引用還是指針

            我看到EffectiveC++2ed中函數(shù)返回對象中的說明感覺以后再也不想讓返回任何東西啦。比較怕。

            但是有的時候不返回任何東西是不行的阿。

            返回引用,返回指針,返回對象到底怎么寫?!

            ——————————————————————————————
            下面是EC中的內(nèi)容

            條款23: 必須返回一個對象時不要試圖返回一個引用

            據(jù)說愛因斯坦曾提出過這樣的建議:盡可能地讓事情簡單,但不要過于簡單。在c++語言中相似的說法應(yīng)該是:盡可能地使程序高效,但不要過于高效。

            一旦程序員抓住了“傳值”在效率上的把柄(參見條款22),他們會變得十分極端,恨不得挖出每一個隱藏在程序中的傳值操作。豈不知,在他們不懈地追求純粹的“傳引用”的過程中,他們會不可避免地犯另一個嚴(yán)重的錯誤:傳遞一個并不存在的對象的引用。這就不是好事了。

            看一個表示有理數(shù)的類,其中包含一個友元函數(shù),用于兩個有理數(shù)相乘:

            class rational {
            public:
            ? rational(int numerator = 0, int denominator = 1);

            ? ...

            private:
            ? int n, d;????????????? // 分子和分母

            friend
            ? const rational????????????????????? // 參見條款21:為什么
            ??? operator*(const rational& lhs,??? // 返回值是const
            ????????????? const rational& rhs)????
            };

            inline const rational operator*(const rational& lhs,
            ??????????????????????????????? const rational& rhs)
            {
            ? return rational(lhs.n * rhs.n, lhs.d * rhs.d);
            }

            很明顯,這個版本的operator*是通過傳值返回對象結(jié)果,如果不去考慮對象構(gòu)造和析構(gòu)時的開銷,你就是在逃避作為一個程序員的責(zé)任。另外一件很明顯的事實是,除非確實有必要,否則誰都不愿意承擔(dān)這樣一個臨時對象的開銷。那么,問題就歸結(jié)于:確實有必要嗎?

            答案是,如果能返回一個引用,當(dāng)然就沒有必要。但請記住,引用只是一個名字,一個其它某個已經(jīng)存在的對象的名字。無論何時看到一個引用的聲明,就要立即問自己:它的另一個名字是什么呢?因為它必然還有另外一個什么名字(見條款m1)。拿operator*來說,如果函數(shù)要返回一個引用,那它返回的必須是其它某個已經(jīng)存在的rational對象的引用,這個對象包含了兩個對象相乘的結(jié)果。

            但,期望在調(diào)用operator*之前有這樣一個對象存在是沒道理的。也就是說,如果有下面的代碼:

            rational a(1, 2);??????????????? // a = 1/2
            rational b(3, 5);??????????????? // b = 3/5
            rational c = a * b;????????????? // c 為 3/10

            期望已經(jīng)存在一個值為3/10的有理數(shù)是不現(xiàn)實的。如果operator* 一定要返回這樣一個數(shù)的引用,就必須自己創(chuàng)建這個數(shù)的對象。

            一個函數(shù)只能有兩種方法創(chuàng)建一個新對象:在堆棧里或在堆上。在堆棧里創(chuàng)建對象時伴隨著一個局部變量的定義,采用這種方法,就要這樣寫operator*:

            // 寫此函數(shù)的第一個錯誤方法
            inline const rational& operator*(const rational& lhs,
            ???????????????????????????????? const rational& rhs)
            {
            ? rational result(lhs.n * rhs.n, lhs.d * rhs.d);
            ? return result;
            }

            這個方法應(yīng)該被否決,因為我們的目標(biāo)是避免構(gòu)造函數(shù)被調(diào)用,但result必須要象其它對象一樣被構(gòu)造。另外,這個函數(shù)還有另外一個更嚴(yán)重的問題,它返回的是一個局部對象的引用,關(guān)于這個錯誤,條款31進行了深入的討論。

            那么,在堆上創(chuàng)建一個對象然后返回它的引用呢?基于堆的對象是通過使用new產(chǎn)生的,所以應(yīng)該這樣寫operator*:

            // 寫此函數(shù)的第二個錯誤方法
            inline const rational& operator*(const rational& lhs,
            ???????????????????????????????? const rational& rhs)
            {
            ? rational *result =
            ??? new rational(lhs.n * rhs.n, lhs.d * rhs.d);
            ? return *result;
            }

            首先,你還是得負(fù)擔(dān)構(gòu)造函數(shù)調(diào)用的開銷,因為new分配的內(nèi)存是通過調(diào)用一個適當(dāng)?shù)臉?gòu)造函數(shù)來初始化的(見條款5和m8)。另外,還有一個問題:誰將負(fù)責(zé)用delete來刪除掉new生成的對象呢?

            實際上,這絕對是一個內(nèi)存泄漏。即使可以說服operator*的調(diào)用者去取函數(shù)返回值地址,然后用delete去刪除它(絕對不可能——條款31展示了這樣的代碼會是什么樣的),但一些復(fù)雜的表達式會產(chǎn)生沒有名字的臨時值,程序員是不可能得到的。例如:

            rational w, x, y, z;

            w = x * y * z;

            兩個對operator*的調(diào)用都產(chǎn)生了沒有名字的臨時值,程序員無法看到,因而無法刪除。(再次參見條款31)

            也許,你會想你比一般的熊——或一般的程序員——要聰明;也許,你注意到在堆棧和堆上創(chuàng)建對象的方法避免不了對構(gòu)造函數(shù)的調(diào)用;也許,你想起了我們最初的目標(biāo)是為了避免這種對構(gòu)造函數(shù)的調(diào)用;也許,你有個辦法可以只用一個構(gòu)造函數(shù)來搞掂一切;也許,你的眼前出現(xiàn)了這樣一段代碼:operator*返回一個“在函數(shù)內(nèi)部定義的靜態(tài)rational對象”的引用:

            // 寫此函數(shù)的第三個錯誤方法
            inline const rational& operator*(const rational& lhs,
            ???????????????????????????????? const rational& rhs)
            {
            ? static rational result;????? // 將要作為引用返回的
            ?????????????????????????????? // 靜態(tài)對象

            ? lhs和rhs 相乘,結(jié)果放進result;

            ? return result;
            }

            這個方法看起來好象有戲,雖然在實際實現(xiàn)上面的偽代碼時你會發(fā)現(xiàn),不調(diào)用一個rational構(gòu)造函數(shù)是不可能給出result的正確值的,而避免這樣的調(diào)用正是我們要談?wù)摰闹黝}。就算你實現(xiàn)了上面的偽代碼,但,你再聰明也不能最終挽救這個不幸的設(shè)計。

            想知道為什么,看看下面這段寫得很合理的用戶代碼:

            bool operator==(const rational& lhs,????? // rationals的operator==
            ??????????????? const rational& rhs);???? //

            rational a, b, c, d;

            ...

            if ((a * b) == (c * d)) {

            ? 處理相等的情況;

            } else {

            ? 處理不相等的情況;

            }

            看出來了嗎?((a*b) == (c*d)) 會永遠為true,不管a,b,c和d是什么值!

            用等價的函數(shù)形式重寫上面的相等判斷語句就很容易明白發(fā)生這一可惡行為的原因了:

            if (operator==(operator*(a, b), operator*(c, d)))

            注意當(dāng)operator==被調(diào)用時,總有兩個operator*剛被調(diào)用,每個調(diào)用返回operator*內(nèi)部的靜態(tài)rational對象的引用。于是,上面的語句實際上是請求operator==對“operator*內(nèi)部的靜態(tài)rational對象的值”和“operator*內(nèi)部的靜態(tài)rational對象的值”進行比較,這樣的比較不相等才怪呢!

            幸運的話,我以上的說明應(yīng)該足以說服你:想“在象operator*這樣的函數(shù)里返回一個引用”實際上是在浪費時間。但我沒幼稚到會相信幸運總會光臨自己。一些人——你們知道這些人是指誰——此刻會在想,“唔,上面那個方法,如果一個靜態(tài)變量不夠用,也許可以用一個靜態(tài)數(shù)組……”

            請就此打住!我們難道還沒受夠嗎?

            我不能讓自己寫一段示例代碼來太高這個設(shè)計,因為即使只抱有上面這種想法都足以令人感到羞愧。首先,你必須選擇一個n,指定數(shù)組的大小。如果n太小,就會沒地方儲存函數(shù)返回值,這和我們前面否定的那個“采用單個靜態(tài)變量的設(shè)計”相比沒有什么改進。如果n太大,就會降低程序的性能,因為函數(shù)第一次被調(diào)用時數(shù)組中每個對象都要被創(chuàng)建。這會帶來n個構(gòu)造函數(shù)和n個析構(gòu)函數(shù)的開銷,即使這個函數(shù)只被調(diào)用一次。如果說"optimization"(最優(yōu)化)是指提高軟件的性能的過程, 那么現(xiàn)在這種做法簡直可以稱為"pessimization"(最差化)。最后,想想怎么把需要的值放到數(shù)組的對象中以及需要多大的開銷?在對象間傳值的最直接的方法是通過賦值,但賦值的開銷又有多大呢?一般來說,它相當(dāng)于調(diào)用一個析構(gòu)函數(shù)(摧毀舊值)再加上調(diào)用一個構(gòu)造函數(shù)(拷貝新值)。但我們現(xiàn)在的目標(biāo)正是為了避免構(gòu)造和析構(gòu)的開銷啊!面對現(xiàn)實吧:這個方法也絕對不能選用。

            所以,寫一個必須返回一個新對象的函數(shù)的正確方法就是讓這個函數(shù)返回一個新對象。對于rational的operator*來說,這意味著要不就是下面的代碼(就是最初看到的那段代碼),要不就是本質(zhì)上和它等價的代碼:

            inline const rational operator*(const rational& lhs,
            ??????????????????????????????? const rational& rhs)
            {
            ? return rational(lhs.n * rhs.n, lhs.d * rhs.d);
            }

            的確,這會導(dǎo)致“operator*的返回值構(gòu)造和析構(gòu)時帶來的開銷”,但歸根結(jié)底它只是用小的代價換來正確的程序運行行為而已。況且,你所擔(dān)心的開銷還有可能永遠不會出現(xiàn):和所有程序設(shè)計語言一樣,c++允許編譯器的設(shè)計者采用一些優(yōu)化措施來提高所生成的代碼的性能,所以,在有些場合,operator*的返回值會被安全地除去(見條款m20)。當(dāng)編譯器采用了這種優(yōu)化時(當(dāng)前大部分編譯器這么做),程序和以前一樣繼續(xù)工作,只不過是運行速度比你預(yù)計的要快而已。

            以上討論可以歸結(jié)為:當(dāng)需要在返回引用和返回對象間做決定時,你的職責(zé)是選擇可以完成正確功能的那個。至于怎么讓這個選擇所產(chǎn)生的代價盡可能的小,那是編譯器的生產(chǎn)商去想的事。

            posted @ 2006-03-24 15:51 Beginning to 編程 閱讀(2933) | 評論 (0)編輯 收藏

            2006年3月23日

            Doxygen 源代碼文檔自動生成器的使用筆記

                 摘要: 在 google 上搜了很久的關(guān)于 Doxygen 使用方法的咚咚,只不過都是英文,而且都很多的規(guī)則。實際上大家只需要告訴基本的規(guī)則就可以。下面是我對 Doxygen 的摸索 ? 首先熟知 Do...  閱讀全文

            posted @ 2006-03-23 22:32 Beginning to 編程 閱讀(18220) | 評論 (4)編輯 收藏

            2006年3月20日

            查錯:下面的程序編譯沒問題,為什么運行會出錯呢

            最近在看吉林大學(xué)的C程序設(shè)計的課件,有一章講到這個函數(shù)動手寫了一下。

            題目:
            編寫一個Insert函數(shù)實現(xiàn)在字符串s中的第i個位置插入字符串s1;
            在VC++2005中編譯這段程序沒有任何的Error和warning但是運行就會錯誤,不知道為什么阿,請高手指點一二。

            #include "stdafx.h"

            #include <iostream>
            using namespace std;

            void Insert(char *s, char *s1, int i)
            {
            ?char *p,*q;
            ?p = s + strlen(s); // p?指向s的末尾+1
            ?q = p + strlen(s1);?//q 指向新構(gòu)造的字符串的\0?
            ?*q = '\0';

            ?//?
            ?for(p--,q--;p>=s+i-1;)
            ?{
            ??*(p--) = *(q--);
            ?}

            ?//
            ?for(p=s+i-1;*s1;)
            ?{
            ??*(p++) = *(s1++);
            ?}
            }


            int _tmain(int argc, _TCHAR* argv[])
            {

            ?char *s = "Student";
            ?char *s1 = "Teacher";

            ?Insert(s,s1,3);

            // 期待的輸出是StuTeacherdent;
            ?cout<<s;


            ?return 0;
            }


            // 還有我如果把insert函數(shù)改成下面的應(yīng)該也是可以的吧

            void Insert2(char *s, char *s1, int i)
            {
            ?char *p,*q;
            ?p = s + strlen(s); // p?指向s的末尾+1
            ?q = p + strlen(s1);?//q 指向新構(gòu)造的字符串的\0?
            ?*q = '\0';

            ?//?
            ?for(p--,q--;p>=s+i-1;)
            ?{
            ??*p-- = *q--;
            ?}

            ?//
            ?for(p=s+i-1;*s1;)
            ?{
            ??*p++ = *s1++;
            ?}
            }

            posted @ 2006-03-20 21:32 Beginning to 編程 閱讀(1194) | 評論 (3)編輯 收藏

            僅列出標(biāo)題  下一頁

            導(dǎo)航

            統(tǒng)計

            常用鏈接

            留言簿(4)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            BlogDev

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            精品久久久久久久久中文字幕| 香蕉久久永久视频| 国产91久久精品一区二区| AV狠狠色丁香婷婷综合久久| 国产伊人久久| 久久亚洲春色中文字幕久久久| 久久久精品一区二区三区| 伊人色综合久久天天人守人婷| 久久精品九九亚洲精品| 狠狠色伊人久久精品综合网 | 国产香蕉97碰碰久久人人| 日本久久中文字幕| 久久精品一区二区国产| 亚洲欧美日韩久久精品第一区 | 久久精品亚洲精品国产欧美| 婷婷伊人久久大香线蕉AV| 午夜精品久久久久久影视777| 国产精品久久影院| 亚洲欧美成人综合久久久| 亚洲欧美另类日本久久国产真实乱对白 | 亚洲成人精品久久| 久久久久久久精品成人热色戒 | 国产成人精品久久二区二区| 久久天天躁夜夜躁狠狠躁2022| 久久精品国产只有精品66| 久久99国产精品久久99果冻传媒 | 久久久国产视频| 久久精品亚洲欧美日韩久久| 94久久国产乱子伦精品免费 | 国产精品久久久99| 青青草国产精品久久| 99久久久久| 久久97久久97精品免视看| 久久精品成人影院| 久久久精品久久久久久| 欧美国产精品久久高清| 久久久人妻精品无码一区| 久久影院午夜理论片无码| 伊人精品久久久久7777| 国产成人无码精品久久久性色| 天天躁日日躁狠狠久久|