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

            來吧,朋友!

            為C++瘋狂

            2009年8月13日

            http://www.scs.stanford.edu/~dm/home/papers/c++-new.html
            posted @ 2009-08-13 14:47 yanghaibao| 編輯 收藏

            2009年8月12日


            一、選擇公司的形式:

            普通的有限責任公司,最低注冊資金3萬元,需要2個或2個以上的股東,

            從06年1月起新的公司法規定,允許1個股東注冊有限責任公司,這種特殊的有限責任公司又稱“一人有限公司”(但公司名稱中不會有“一人”字樣,執照上會注明“自然人獨資”),最低注冊資金10萬元。如果只有你一個人作為股東,則選擇一人有限公司,最低注冊資金10萬元;如果你和朋友、家人合伙投資創業,可選擇普通的有限公司,最低注冊資金3萬元。建議你準備好注冊資金3萬元。

            二、注冊公司所需的注冊資料:
            (1)個人資料(身份證、法人戶口本復印件或戶籍證明、居住地址、電話號碼)
            (2)注冊資金
            (3)擬訂注冊公司名稱若干
            (4)公司經營范圍
            (5)租房房產證、租賃合同
            (6)公司住所
            (7)股東名冊及股東聯系電話、聯系地址
            (8)公司的機構及其產生辦法、職權、議事規則
            (9)公司章程

            三、注冊公司的步驟:

            1.核名:到工商局去領取一張“企業(字號)名稱預先核準申請表”,填寫你準備取的公司名稱,由工商局上工商局內部網檢索是否有重名,如果沒有重名,就可以使用這個名稱,就會核發一張“企業(字號)名稱預先核準通知書”。工商名稱核準費是40元,交給工商局。 40元可以幫你檢索5個名字,很多名字重復,所以一般常見的名字就不用試了,免得花冤枉錢。

            2.租房: 去專門的寫字樓租一間辦公室,如果你自己有廠房或者辦公室也可以,有的地方不允許在居民樓里辦公。 你要交房租給所租辦公室的房東(所有權人),假設辦公室的房租是1000元/月,一般起租最少6個月,6個月的房租是6000元。

            3.簽訂租房合同:你要與你所租的辦公室的房東簽定租房合同,并讓房東提供房產證的復印件。租房合同打印費5份15元,房產證復印件5張2.5元。

            4.買租房的印花稅:你要到稅務局去買印花稅,按年租金的千分之一的稅率購買,貼在房租合同的首頁。例如你的每年房租是1.2萬元,那就要買12元錢的印花稅,后面凡是需要用到房租合同的地方,都需要是貼了印花稅的合同復印件。

            5.編寫“公司章程”:可以在工商局網站下載“公司章程”的樣本,修改一下就可以了。章程的最后由所有股東簽名。 假設章程打印5份(股東2人各2份、工商局1份、銀行1份、會計師事務所1份),章程打印費15元、下載公司章程的上網費2元。

            6.刻私章: 去街上刻章的地方刻一個私章,給他們講刻法人私章(方形的)。刻章費用20元。

            7.到會計師事務所領取“銀行詢征函”:聯系一家會計師事務所,領取一張“銀行詢征函”,必須是原件,會計師事務所蓋鮮章。如果你不清楚,可以看報紙上的分類廣告,有很多會計師事務所的廣告。銀行詢征函10元。

            8.去銀行開立公司驗資戶: 所有股東帶上自己入股的那一部分錢到銀行,帶上公司章程、工商局發的核名通知、法人代表的私章、身份證、用于驗資的錢、空白詢征函表格,到銀行去開立公司帳戶,你要告訴銀行是開驗資戶。開立好公司帳戶后,各個股東按自己出資額向公司帳戶中存入相應的錢。 銀行會發給每個股東繳款單、并在詢征函上蓋銀行的章。公司驗資戶開戶費20元。

            注意:公司法規定,注冊公司時,投資人(股東)必須繳納足額的資本,可以以貸幣形式(也就是人民幣)出資,也可以以實物(如汽車、房產、知識產權等)出資。到銀行辦的只是貨幣出資這一部分,如果你有實物、房產等作為出資的,需要到會計師事務所鑒定其價值后再以其實際價值出資,比較麻煩,因此建議你直接拿錢來出資,公司法不管你用什么手段拿的錢,自己的也好、借的也好,只要如數繳足出資款即可。

            9.辦理驗資報告:拿著銀行出具的股東繳款單、銀行蓋章后的詢征函,以及公司章程、核名通知、房租合同、房產證復印件,到會計師事務所辦理驗資報告,會計師事務師驗資報告按注冊資本收費。50萬元以下注冊資金驗資費500元。

            10.注冊公司:到工商局領取公司設立登記的各種表格,包括設立登記申請表、股東(發起人)名單、董事經理監理情況、法人代表登記表、指定代表或委托代理人登記表。注冊登記費,按注冊資金的萬分之8收取。填好后,連同核名通知、公司章程、房租合同、房產證復印件、驗資報告一起交給工商局。大概3個工作日后可領取執照。注冊公司手續費300元。

            11.憑營業執照,到公安局特行科指定的刻章社,去刻公章、財務章。后面步驟中,均需要用到公章或財務章。公章50元,財務章50元。

            12.辦理企業組織機構代碼證:憑營業執照到技術監督局辦理組織機構代碼證,費用是80元。辦這個證需要半個月,技術監督局會首先發一個預先受理代碼證明文件,憑這個文件就可以辦理后面的稅務登記證、銀行基本戶開戶手續了。

            13.去銀行開基本戶:憑營業執照、組織機構代碼證,去銀行開立基本帳號。最好是在原來辦理驗資時的那個銀行的同一網點去辦理,否則,會多收100元的驗資帳戶費用。 開基本戶需要填很多表,你最好把能帶齊的東西全部帶上,要不然要跑很多趟,包括營業執照正本原件、身份證、組織機構代碼證、公財章、法人章。

            開基本戶時,還需要購買一個密碼器(從2005年下半年起,大多銀行都有這個規定),今后你的公司開支票、劃款時,都需要使用密碼器來生成密碼。公司基本帳號開戶費20元,密碼器280元。

            14.辦理稅務登記:領取執照后,30日內到當地稅務局申請領取稅務登記證。一般的公司都需要辦理2種稅務登記證,即國稅和地稅。費用是各40元,共80元。

            15.請兼職會計:辦理稅務登記證時,必須有一個會計,因為稅務局要求提交的資料其中有一項是會計資格證和身份證。你可先請一個兼職會計,小公司剛開始請的兼職會計一般200元工資就可以了。

            16.申請領購發票:如果你的公司是銷售商品的,應該到國稅去申請發票,如果是服務性質的公司,則到地稅申領發票。 開始可先領購500元的發票。

            最后就開始營業了。

            四、注冊公司的費用:
            1、工商局工商名稱核準,40元
            2、公司辦公室房租6個月,6000元
            3、租房合同打印費5份15元,房產證復印件5張2.5元
            4、租房的印花稅12元
            5、下載公司章程的上網費2元,公司章程打印費15元
            6、刻法人私章20元
            7、會計師事務所的銀行詢征函10元
            8、銀行開立公司驗資戶開戶費20元
            9、會計師事務所辦理驗資報告500元
            10、工商局注冊公司手續費300元,信息卡120元
            11、公章2個120元,財務章1個60元
            12、技術監督局辦理組織機構代碼證148元
            13、銀行開立公司基本帳號開戶費20元、密碼器280元
            14、國稅稅務登記證60元,地稅稅務登記證60元
            15、兼職會計工資,200元
            16、申請領購發票,500元
            合計:8502.5元
            如果不算房租、會計工資、發票,則合計1802.5元。

            注冊資本最少3萬元。

            注冊登記費按注冊資本的0.08%(1000萬以內),0.04%(1000萬以上的超過部分)收取

            營業稅:銷售商品的公司,按所開發票額的4%征收增殖稅;提供服務的公司,按所開發票額的5%征收營業稅。

            所得稅:對企業的純利潤征收18-33%的企業所得稅。
            利潤收入在3萬元(含3萬元)以下的稅率為18%,利潤收入在3萬元以上10萬元(含10萬元)的稅率為27%,10萬元以上的為33%。

            五、注冊公司的相關說明:

            1.注冊公司會不到半年時間,最快需要20天時間。地區不同注冊公司的費用也有所不同。

            2.要注冊一個公司,首先想好經營什么,怎樣經營好,再來注冊。要不,注冊了也沒有用,注冊了公司是需要很多成本的,不是一件“好玩”的事情。

            3.注冊個體簡單易辦;而注冊公司要有章程、合同,要驗資,程序挺多的。 在投入不是太多時,還是注冊個體為好。

            4.前期可行性分析調查,建議你自己認真的考慮一下

            5.公司必須建立健全的會計制度,你可能擔心自己不會,怎么辦?剛開始成立的公司,業務少,對會計的工作量也非常小,你可以請一個兼職會計,每個月到你的公司幫你建帳,二、三天時間就夠了,給他200-500左右的工資即可。

            6.每個月1日-10日按時向稅務申報稅,即使沒有開展業務不需要繳稅,也要進行零申報,否則會被罰款的。罰款額度超過一天100元。營業執照辦理下來后一個月內必須辦理稅務登記。每年3-6月年定時年檢營業執照。

            7.對企業所得稅,做帳很關鍵,如果帳面上你的利潤很多,那稅率就高。所以,平常的購買設備都要開發票,你吃飯、坐車的票都留起來,可以做為你的企業運作成本。

            8.營業稅是對營業額征稅,不管你賺沒有賺錢,只有發生了交易,開了發票,就要征稅;所得稅,是對利潤征稅,利潤就是營業額扣減各種成本后剩余的錢,只有賺了錢,才會征所得稅。

            9.有限責任公司可以注冊分公司。

            10.開辦費是指企業在籌建期間發生的費用,包括籌建期人員工資、辦公費、培訓費、差旅費、印刷費、注冊登記費以及不計入固定資產和無形資產購建成本的匯兌損益和利息支出。籌建期是指企業被批準籌建之日起至開始生產、經營(包括試生產、試營業)之日的期間。
            posted @ 2009-08-12 16:33 yanghaibao| 編輯 收藏

            2009年7月24日

             c++中的explicit關鍵字用來修飾類的構造函數,表明該構造函數是顯式的,既然有"顯式"那么必然就有"隱式",那么什么是顯示而什么又是隱式的呢?

            如果c++類的構造函數有一個參數,那么在編譯的時候就會有一個缺省的轉換操作:將該構造函數對應數據類型的數據轉換為該類對象,如下面所示:
            class MyClass
            {
            public:
            MyClass( int num );
            }
            ....
            MyClass obj = 10; //ok,convert int to MyClass
            在上面的代碼中編譯器自動將整型轉換為MyClass類對象,實際上等同于下面的操作:
            MyClass temp(10);
            MyClass obj = temp;
            上面的所有的操作即是所謂的"隱式轉換"。

            如果要避免這種自動轉換的功能,我們該怎么做呢?嘿嘿這就是關鍵字explicit的作用了,將類的構造函數聲明為"顯示",也就是在聲明構造函數的時候前面添加上explicit即可,這樣就可以防止這種自動的轉換操作,如果我們修改上面的MyClass類的構造函數為顯示的,那么下面的代碼就不能夠編譯通過了,如下所示:
            class MyClass
            {
            public:
            explicit MyClass( int num );
            }
            ....
            MyClass obj = 10; //err,can't non-explict convert

            class isbn_mismatch:public std::logic_error{
            public:
            explicit isbn_missmatch(const std::string &s):std:logic_error(s){}
            isbn_mismatch(const std::string &s,const std::string &lhs,const std::string &rhs):
            std::logic_error(s),left(lhs),right(rhs){}
            const std::string left,right;
            virtual ~isbn_mismatch() throw(){}
            };


            Sales_item& operator+(const Sales_item &lhs,const Sales_item rhs)
            {
            if(!lhs.same_isbn(rhs))
               throw isbn_mismatch("isbn missmatch",lhs.book(),rhs.book());
            Sales_item ret(lhs);
            ret+rhs;
            return ret;
            }


            Sales_item item1,item2,sum;
            while(cin>>item1>>item2)
            {
            try{
               sun=item1+item2;
            }catch(const isbn_mismatch &e)
            {
               cerr<<e.what()<<"left isbn is:"<<e.left<<"right isbn is:"<<e.right<<endl;
            }
            }

            用于用戶自定義類型的構造函數,指定它是默認的構造函數,不可用于轉換構造函數.因為構造函數有三種:1拷貝構造函數2轉換構造函數3一般的構造函數(我自己的術語^_^)
            另:如果一個類或結構存在多個構造函數時,explicit 修飾的那個構造函數就是默認的

            class isbn_mismatch:public std::logic_error{
            public:
            explicit isbn_missmatch(const std::string &s):std:logic_error(s){}
            isbn_mismatch(const std::string &s,const std::string &lhs,const std::string &rhs):
            std::logic_error(s),left(lhs),right(rhs){}
            const std::string left,right;
            virtual ~isbn_mismatch() throw(){}
            };


            Sales_item& operator+(const Sales_item &lhs,const Sales_item rhs)
            {
            if(!lhs.same_isbn(rhs))
               throw isbn_mismatch("isbn missmatch",lhs.book(),rhs.book());
            Sales_item ret(lhs);
            ret+rhs;
            return ret;
            }


            Sales_item item1,item2,sum;
            while(cin>>item1>>item2)
            {
            try{
               sun=item1+item2;
            }catch(const isbn_mismatch &e)
            {
               cerr<<e.what()<<"left isbn is:"<<e.left<<"right isbn is:"<<e.right<<endl;
            }
            }

             

            這個 《ANSI/ISO C++ Professional Programmer's Handbook 》是這樣說的

            explicit Constructors
            A constructor that takes a single argument is, by default, an implicit conversion operator, which converts its argument to
            an object of its class (see also Chapter 3, "Operator Overloading"). Examine the following concrete example:
            class string
            {
            private:
            int size;
            int capacity;
            char *buff;
            public:
            string();
            string(int size); // constructor and implicit conversion operator
            string(const char *); // constructor and implicit conversion operator
            ~string();
            };
            Class string has three constructors: a default constructor, a constructor that takes int, and a constructor that
            constructs a string from const char *. The second constructor is used to create an empty string object with an
            initial preallocated buffer at the specified size. However, in the case of class string, the automatic conversion is
            dubious. Converting an int into a string object doesn't make sense, although this is exactly what this constructor does.

            Consider the following:
            int main()
            {
            string s = "hello"; //OK, convert a C-string into a string object
            int ns = 0;
            s = 1; // 1 oops, programmer intended to write ns = 1,
            }
            In the expression s= 1;, the programmer simply mistyped the name of the variable ns, typing s instead. Normally,
            the compiler detects the incompatible types and issues an error message. However, before ruling it out, the compiler first
            searches for a user-defined conversion that allows this expression; indeed, it finds the constructor that takes int.
            Consequently, the compiler interprets the expression s= 1; as if the programmer had written
            s = string(1);
            You might encounter a similar problem when calling a function that takes a string argument. The following example
            can either be a cryptic coding style or simply a programmer's typographical error. However, due to the implicit
            conversion constructor of class string, it will pass unnoticed:
            int f(string s);
            int main()
            {
            f(1); // without a an explicit constructor,
            //this call is expanded into: f ( string(1) );
            //was that intentional or merely a programmer's typo?
            }
            'In order to avoid such implicit conversions, a constructor that takes one argument needs to be declared explicit:
            class string
            {
            //...
            public:
            explicit string(int size); // block implicit conversion
            string(const char *); //implicit conversion
            ~string();
            };
            An explicit constructor does not behave as an implicit conversion operator, which enables the compiler to catch the
            typographical error this time:
            int main()
            {
            string s = "hello"; //OK, convert a C-string into a string object
            int ns = 0;
            s = 1; // compile time error ; this time the compiler catches the typo
            }
            Why aren't all constructors automatically declared explicit? Under some conditions, the automatic type conversion is
            useful and well behaved. A good example of this is the third constructor of string:
            string(const char *);

            The implicit type conversion of const char * to a string object enables its users to write the following:
            string s;
            s = "Hello";
            The compiler implicitly transforms this into
            string s;
            //pseudo C++ code:
            s = string ("Hello"); //create a temporary and assign it to s
            On the other hand, if you declare this constructor explicit, you have to use explicit type conversion:
            class string
            {
            //...
            public:
            explicit string(const char *);
            };
            int main()
            {
            string s;
            s = string("Hello"); //explicit conversion now required
            return 0;
            }
            Extensive amounts of legacy C++ code rely on the implicit conversion of constructors. The C++ Standardization
            committee was aware of that. In order to not make existing code break, the implicit conversion was retained. However, a
            new keyword, explicit, was introduced to the languageto enable the programmer to block the implicit conversion
            when it is undesirable. As a rule, a constructor that can be invoked with a single argument needs to be declared
            explicit. When the implicit type conversion is intentional and well behaved, the constructor can be used as an
            implicit conversion operator.

            網上找的講的最好的貼:

            C++ 中 explicit 關鍵字的作用
            在 C++ 中, 如果一個類有只有一個參數的構造函數,C++ 允許一種特殊的聲明類變量的方式。在這種情況下,可以直接將一個對應于構造函數參數類型的數據直接賦值給類變量,編譯器在編譯時會自動進行類型轉換,將對應于構造函數參數類型的數據轉換為類的對象。 如果在構造函數前加上 explicit 修飾詞, 則會禁止這種自動轉換,在這種情況下,即使將對應于構造函數參數類型的數據直接賦值給類變量,編譯器也會報錯。

            下面以具體實例來說明。

            建立people.cpp 文件,然后輸入下列內容:

            class People
            {
            public:
            int age;
            explicit People (int a)
             {
              age=a;
             }
            };
            void foo ( void )
            {
             People p1(10);  //方式一
             People* p_p2=new People(10); //方式二
             People p3=10; //方式三
            }
            這段 C++ 程序定義了一個類 people ,包含一個構造函數, 這個構造函數只包含一個整形參數 a ,可用于在構造類時初始化 age 變量。

            然后定義了一個函數foo,在這個函數中我們用三種方式分別創建了三個10歲的“人”。第一種是最一般的類變量聲明方式。第二種方式其實是聲明了一個people類的指針變量,然后在堆中動態創建了一個people實例,并把這個實例的地址賦值給了p_p2。第三種方式就是我們所說的特殊方式,為什么說特殊呢?我們都知道,C/C++是一種強類型語言,不同的數據類型是不能隨意轉換的,如果要進行類型轉換,必須進行顯式強制類型轉換,而這里,沒有進行任何顯式的轉換,直接將一個整型數據賦值給了類變量p3。

            因此,可以說,這里進行了一次隱式類型轉換,編譯器自動將對應于構造函數參數類型的數據轉換為了該類的對象,因此方式三經編譯器自動轉換后和方式一最終的實現方式是一樣的。

            不相信? 耳聽為虛,眼見為實,讓我們看看底層的實現方式。

            為了更容易比較方式一和方式三的實現方式,我們對上面的代碼作一點修改,去除方式二:

            void foo ( void )
            {
             People p1(10);  //方式一
             People p3=10; //方式三
            }
            去除方式二的原因是方式二是在堆上動態創建類實例,因此會有一些額外代碼影響分析。修改完成后,用下列命令編譯 people.cpp

            $ gcc -S people.cpp

            "-S"選項是GCC輸出匯編代碼。命令執行后,默認生成people.s。 關鍵部分內容如下:

            .globl _Z3foov
            .type _Z3foov, @function
            _Z3foov:
            .LFB5:
             pushl %ebp
            .LCFI2:
             movl %esp, %ebp
            .LCFI3:
             subl $24, %esp
            .LCFI4:
             movl $10, 4(%esp)
             leal -4(%ebp), %eax
             movl %eax, (%esp)
             call _ZN6PeopleC1Ei
             movl $10, 4(%esp)
             leal -8(%ebp), %eax
             movl %eax, (%esp)
             call _ZN6PeopleC1Ei
             leave
             ret

            看“.LCFI4” 行后面的東西,1-4行和5-8行幾乎一模一樣,1-4行即為方式一的匯編代碼,5-8即為方式三的匯編代碼。 細心的你可能發現2和6行有所不同,一個是 -4(%ebp) 而另一個一個是 -8(%ebp) ,這分別為類變量P1和P3的地址。

            對于不可隨意進行類型轉換的強類型語言C/C++來說, 這可以說是C++的一個特性。哦,今天好像不是要說C++的特性,而是要知道explicit關鍵字的作用?

            explicit關鍵字到底是什么作用呢? 它的作用就是禁止這個特性。如文章一開始而言,凡是用explicit關鍵字修飾的構造函數,編譯時就不會進行自動轉換,而會報錯。

            讓我們看看吧! 修改代碼:

            class People
            {
            public:
            int age;
            explicit People (int a)
             {
              age=a;
             }
            };
            然后再編譯:
            $ gcc -S people.cpp
            編譯器立馬報錯:
            people.cpp: In function ‘void foo()’:
            people.cpp:23: 錯誤:請求從 ‘int’ 轉換到非標量類型 ‘People’
            posted @ 2009-07-24 16:49 yanghaibao| 編輯 收藏

            2009年7月22日

            軟件設計中會碰到這樣的關系:一個對象依賴于另一個對象,必須根據后者的狀態更新自己的狀態,可以把后者稱作目標對象,前者稱作觀察者對象。不但觀察者依賴于目標,當目標的狀態改變時也要通知觀察者,這就出現了雙向的依賴。兩個對象互相依賴的后果是它們必須一起復用。如果一個目標有多個觀察者,那么目標也依賴所有觀察者,從而目標對象無法獨立復用。如何消除目標和觀察者之間的互相依賴呢?觀察者模式幫助我們解決這個問題。

            觀察者模式把目標對觀察者的依賴進行抽象:使目標只知道自己有若干觀察者,但不知道這些觀察者具體是誰,可能有多少個;當目標狀態改變時只要給這些觀察者一個通知,不必作更多的事情。這樣目標對觀察者的依賴就達到了抽象和最小,而目標對具體觀察者的依賴被解除了。

            類圖如下:

            Observer.JPG

            Subject 對象保存一個Observer引用的列表,當我們讓一個ConcreteObserver對象觀察Subject對象時,調用后者的Attach()方法,將前者的引用加入該列表中。當Subject對象狀態改變時,它調用自身的Notify方法,該方法調用列表中每一個Observer的 Update()方法。一個ConcreteObserver只要重定義Update()就能收到通知,作為對通知的響應,Update()調用 Subject對象的getStatus()獲取數據,然后更新自身。當不需要繼續觀察時,ConcreteObserver對象調用Subject對象的Detach()方法,其引用被從列表中移除。

            解除目標對具體觀察者的依賴以后,很容易增加新的具體觀察者,因為不受依賴的方面就可以自由變化;而目標也可以獨立地復用,因為無所依賴的方面就可以不受影響。

            以上主要考慮了一個目標有多個觀察者的情況,我們設法解除了目標對具體觀察者的依賴,使具體觀察者的種類和數目容易改變。有時候一個觀察者觀察多個目標也是有意義的,在前面的類圖中,觀察者對具體目標的依賴仍然存在,因此無法適應目標方面的變化。怎樣抽象這種依賴呢?使觀察者只知道若干個目標會向自己發出通知,而不知道這些目標具體是誰,可能有多少個;在目標向觀察者發送通知時,將一個自身的引用作為參數,然后觀察者調用其抽象方法就可以獲得目標狀態。這就使得觀察者對目標的依賴是抽象的,觀察者對具體目標的依賴被解除了。

            類圖如下:

            Observer2.JPG

            參考資料:

            1.《設計模式-可復用面向對象軟件的基礎》/Erich Gamma等著,李英軍等譯 機械工業出版社
            posted @ 2009-07-22 23:19 yanghaibao| 編輯 收藏
            起學習 NT/2000方法:

            #include <windows.h>
            #include <conio.h>
            #include <stdio.h>

            #define SystemBasicInformation 0
            #define SystemPerformanceInformation 2
            #define SystemTimeInformation 3

            #define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 (double)((x).LowPart))

            typedef struct
            {
            DWORD dwUnknown1;
            ULONG uKeMaximumIncrement;
            ULONG uPageSize;
            ULONG uMmNumberOfPhysicalPages;
            ULONG uMmLowestPhysicalPage;
            ULONG uMmHighestPhysicalPage;
            ULONG uAllocationGranularity;
            PVOID pLowestUserAddress;
            PVOID pMmHighestUserAddress;
            ULONG uKeActiveProcessors;
            BYTE bKeNumberProcessors;
            BYTE bUnknown2;
            WORD wUnknown3;
            } SYSTEM_BASIC_INFORMATION;

            typedef struct
            {
            LARGE_INTEGER liIdleTime;
            DWORD dwSpare[76];
            } SYSTEM_PERFORMANCE_INFORMATION;

            typedef struct
            {
            LARGE_INTEGER liKeBootTime;
            LARGE_INTEGER liKeSystemTime;
            LARGE_INTEGER liExpTimeZoneBias;
            ULONG uCurrentTimeZoneId;
            DWORD dwReserved;
            } SYSTEM_TIME_INFORMATION;


            // ntdll!NtQuerySystemInformation (NT specific!)
            //
            // The function copies the system information of the
            // specified type into a buffer
            //
            // NTSYSAPI
            // NTSTATUS
            // NTAPI
            // NtQuerySystemInformation(
            // IN UINT SystemInformationClass, // information type
            // OUT PVOID SystemInformation, // pointer to buffer
            // IN ULONG SystemInformationLength, // buffer size in bytes
            // OUT PULONG ReturnLength OPTIONAL // pointer to a 32-bit
            // // variable that receives
            // // the number of bytes
            // // written to the buffer
            // );
            typedef LONG (WINAPI *PROCNTQSI)(UINT,PVOID,ULONG,PULONG);

            PROCNTQSI NtQuerySystemInformation;


            void main(void)
            {
            SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
            SYSTEM_TIME_INFORMATION SysTimeInfo;
            SYSTEM_BASIC_INFORMATION SysBaseInfo;
            double dbIdleTime;
            double dbSystemTime;
            LONG status;
            LARGE_INTEGER liOldIdleTime = {0,0};
            LARGE_INTEGER liOldSystemTime = {0,0};

            NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
            GetModuleHandle("ntdll"),
            "NtQuerySystemInformation"
            );

            if (!NtQuerySystemInformation)
            return;

            // get number of processors in the system
            status = NtQuerySystemInformation(SystemBasicInformation,&SysBaseInfo,sizeof(SysBaseInfo),NULL);
            if (status != NO_ERROR)
            return;

            printf("\nCPU Usage (press any key to exit): ");
            while(!_kbhit())
            {
            // get new system time
            status = NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);
            if (status!=NO_ERROR)
            return;

            // get new CPU's idle time
            status = NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);
            if (status != NO_ERROR)
            return;

            // 本文轉自 C Builder研究 - http://www.ccrun.com/article.asp?i=424&d=7jw23a
            // if it's a first call - skip it
            if (liOldIdleTime.QuadPart != 0)
            {
            // CurrentValue = NewValue - OldValue
            dbIdleTime = Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime);
            dbSystemTime = Li2Double(SysTimeInfo.liKeSystemTime) - Li2Double(liOldSystemTime);

            // CurrentCpuIdle = IdleTime / SystemTime
            dbIdleTime = dbIdleTime / dbSystemTime;

            // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
            dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SysBaseInfo.bKeNumberProcessors 0.5;

            printf("\b\b\b\b=%%",(UINT)dbIdleTime);
            }

            // store new CPU's idle and system time
            liOldIdleTime = SysPerfInfo.liIdleTime;
            liOldSystemTime = SysTimeInfo.liKeSystemTime;

            // wait one second
            Sleep(1000);
            }
            printf("\n");
            }

            //-------------------------------------------------------------

            W9X:
            #include <windows.h>
            #include <conio.h>
            #include <stdio.h>

            void main(void)
            {
            HKEY hkey;
            DWORD dwDataSize;
            DWORD dwType;
            DWORD dwCpuUsage;

            // starting the counter
            if ( RegOpenKeyEx( HKEY_DYN_DATA,
            "PerfStats\\StartStat",
            0,KEY_ALL_ACCESS,
            &hkey ) != ERROR_SUCCESS)
            return;

            dwDataSize=sizeof(DWORD);
            RegQueryValueEx( hkey,
            "KERNEL\\CPUUsage",
            NULL,&dwType,
            (LPBYTE)&dwCpuUsage,
            &dwDataSize );

            RegCloseKey(hkey);

            // geting current counter's value
            if ( RegOpenKeyEx( HKEY_DYN_DATA,
            "PerfStats\\StatData",
            0,KEY_READ,
            &hkey ) != ERROR_SUCCESS)
            return;

            printf("\nCPU Usage (press any key to exit): ");
            while(!_kbhit())
            {
            dwDataSize=sizeof(DWORD);
            RegQueryValueEx( hkey,
            "KERNEL\\CPUUsage",
            NULL,&dwType,
            (LPBYTE)&dwCpuUsage,
            &dwDataSize );
            Sleep(500);
            printf("\b\b\b\b=%%",dwCpuUsage);
            }
            printf("\n");

            RegCloseKey(hkey);

            // stoping the counter
            if ( RegOpenKeyEx( HKEY_DYN_DATA,
            "PerfStats\\StopStat",
            0,KEY_ALL_ACCESS,
            &hkey ) != ERROR_SUCCESS)
            return;

            dwDataSize=sizeof(DWORD);
            RegQueryValueEx( hkey,
            "KERNEL\\CPUUsage",
            NULL,&dwType,
            (LPBYTE)&dwCpuUsage,
            &dwDataSize );

            RegCloseKey(hkey);
            } NT/2000方法:

            #include <windows.h>
            #include <conio.h>
            #include <stdio.h>

            #define SystemBasicInformation 0
            #define SystemPerformanceInformation 2
            #define SystemTimeInformation 3

            #define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 (double)((x).LowPart))

            typedef struct
            {
            DWORD dwUnknown1;
            ULONG uKeMaximumIncrement;
            ULONG uPageSize;
            ULONG uMmNumberOfPhysicalPages;
            ULONG uMmLowestPhysicalPage;
            ULONG uMmHighestPhysicalPage;
            ULONG uAllocationGranularity;
            PVOID pLowestUserAddress;
            PVOID pMmHighestUserAddress;
            ULONG uKeActiveProcessors;
            BYTE bKeNumberProcessors;
            BYTE bUnknown2;
            WORD wUnknown3;
            } SYSTEM_BASIC_INFORMATION;

            typedef struct
            {
            LARGE_INTEGER liIdleTime;
            DWORD dwSpare[76];
            } SYSTEM_PERFORMANCE_INFORMATION;

            typedef struct
            {
            LARGE_INTEGER liKeBootTime;
            LARGE_INTEGER liKeSystemTime;
            LARGE_INTEGER liExpTimeZoneBias;
            ULONG uCurrentTimeZoneId;
            DWORD dwReserved;
            } SYSTEM_TIME_INFORMATION;


            // ntdll!NtQuerySystemInformation (NT specific!)
            //
            // The function copies the system information of the
            // specified type into a buffer
            //
            // NTSYSAPI
            // NTSTATUS
            // NTAPI
            // NtQuerySystemInformation(
            // IN UINT SystemInformationClass, // information type
            // OUT PVOID SystemInformation, // pointer to buffer
            // IN ULONG SystemInformationLength, // buffer size in bytes
            // OUT PULONG ReturnLength OPTIONAL // pointer to a 32-bit
            // // variable that receives
            // // the number of bytes
            // // written to the buffer
            // );
            typedef LONG (WINAPI *PROCNTQSI)(UINT,PVOID,ULONG,PULONG);

            PROCNTQSI NtQuerySystemInformation;


            void main(void)
            {
            SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
            SYSTEM_TIME_INFORMATION SysTimeInfo;
            SYSTEM_BASIC_INFORMATION SysBaseInfo;
            double dbIdleTime;
            double dbSystemTime;
            LONG status;
            LARGE_INTEGER liOldIdleTime = {0,0};
            LARGE_INTEGER liOldSystemTime = {0,0};

            NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(
            GetModuleHandle("ntdll"),
            "NtQuerySystemInformation"
            );

            if (!NtQuerySystemInformation)
            return;

            // get number of processors in the system
            status = NtQuerySystemInformation(SystemBasicInformation,&SysBaseInfo,sizeof(SysBaseInfo),NULL);
            if (status != NO_ERROR)
            return;

            printf("\nCPU Usage (press any key to exit): ");
            while(!_kbhit())
            {
            // get new system time
            status = NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);
            if (status!=NO_ERROR)
            return;

            // get new CPU's idle time
            status = NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);
            if (status != NO_ERROR)
            return;

            // 本文轉自 C Builder研究 - http://www.ccrun.com/article.asp?i=424&d=7jw23a
            // if it's a first call - skip it
            if (liOldIdleTime.QuadPart != 0)
            {
            // CurrentValue = NewValue - OldValue
            dbIdleTime = Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime);
            dbSystemTime = Li2Double(SysTimeInfo.liKeSystemTime) - Li2Double(liOldSystemTime);

            // CurrentCpuIdle = IdleTime / SystemTime
            dbIdleTime = dbIdleTime / dbSystemTime;

            // CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors
            dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SysBaseInfo.bKeNumberProcessors 0.5;

            printf("\b\b\b\b=%%",(UINT)dbIdleTime);
            }

            // store new CPU's idle and system time
            liOldIdleTime = SysPerfInfo.liIdleTime;
            liOldSystemTime = SysTimeInfo.liKeSystemTime;

            // wait one second
            Sleep(1000);
            }
            printf("\n");
            }

            //-------------------------------------------------------------

            W9X:
            #include <windows.h>
            #include <conio.h>
            #include <stdio.h>

            void main(void)
            {
            HKEY hkey;
            DWORD dwDataSize;
            DWORD dwType;
            DWORD dwCpuUsage;

            // starting the counter
            if ( RegOpenKeyEx( HKEY_DYN_DATA,
            "PerfStats\\StartStat",
            0,KEY_ALL_ACCESS,
            &hkey ) != ERROR_SUCCESS)
            return;

            dwDataSize=sizeof(DWORD);
            RegQueryValueEx( hkey,
            "KERNEL\\CPUUsage",
            NULL,&dwType,
            (LPBYTE)&dwCpuUsage,
            &dwDataSize );

            RegCloseKey(hkey);

            // geting current counter's value
            if ( RegOpenKeyEx( HKEY_DYN_DATA,
            "PerfStats\\StatData",
            0,KEY_READ,
            &hkey ) != ERROR_SUCCESS)
            return;

            printf("\nCPU Usage (press any key to exit): ");
            while(!_kbhit())
            {
            dwDataSize=sizeof(DWORD);
            RegQueryValueEx( hkey,
            "KERNEL\\CPUUsage",
            NULL,&dwType,
            (LPBYTE)&dwCpuUsage,
            &dwDataSize );
            Sleep(500);
            printf("\b\b\b\b=%%",dwCpuUsage);
            }
            printf("\n");

            RegCloseKey(hkey);

            // stoping the counter
            if ( RegOpenKeyEx( HKEY_DYN_DATA,
            "PerfStats\\StopStat",
            0,KEY_ALL_ACCESS,
            &hkey ) != ERROR_SUCCESS)
            return;

            dwDataSize=sizeof(DWORD);
            RegQueryValueEx( hkey,
            "KERNEL\\CPUUsage",
            NULL,&dwType,
            (LPBYTE)&dwCpuUsage,
            &dwDataSize );

            RegCloseKey(hkey);
            }
            posted @ 2009-07-22 18:11 yanghaibao| 編輯 收藏

            Introduction

            One of the interesting features I found in C# is a ?Events and Delegates? concept. The idea is good but not new in Object Oriented Programming, it is one of the most frequently used concepts in programming, sometimes referred to as ?Observer? or ?Document/View? design pattern. Classical formulation of it could be found in ?Design Patterns, Elements of Reusable Object Oriented Software? by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (The Gang of Four).

            This concept is used when you want some information stored in one object, called ?model? (subject) to be watched by others, called ?views? (observers). Each time when information is changed in the ?model?, ?views? attached to the model should receive notification and update there states accordingly to the changed ?model?.

            Classical implementation described in ?Design Patterns?:

            As it is seen from the class diagram, concrete models should be derived from Subject class and views from Observer. Any time the state of Subject is changed, it calls notify method which notifies all observers attached to the Subject.

            Collapse Copy Code
            void Subject::notify()
            {
            for(int i=0; i<observes.size(); i++)
            observers[i]->update();
            }

            In many applications, this straightforward implementation is good enough, but things are getting ugly when you have different kinds of changes in the ?subject? and you want to pass different types of parameters to the ?views?.

            One of the examples for complex ?Model?/?View? relations is a GUI control attached to its processing function. Each time the control?s state is changed, process function is called with parameters indicating new state of the control.

            These kinds of problems are solved in C# by the introduction of ?Events and Delegates? concept. The resolution of the problem is easier in C#, because all classes are inherited from the same ?object? class.

            At the beginning, I thought why we do not have this nice ?Events and Delegates? thing in standard C++, but then I came to the conclusion that C++ does not need it.

            C++ language is powerful enough to express ?Events? and ?Delegates? concept in terms of already existing primitives. Proposed design makes it possible to "connect" different methods with different number of parameters belonging to unrelated classes to the ?model?.

            The keys for this solution are C++ templates (generic types) and pointes to member functions.

            Using Code

            Suppose we have a class MySubject that has internal information connected to different views, it produces three different types of events called int_event, double_event and triple_event with different types and numbers of parameters.

            Collapse Copy Code
            class MySubject
            {
            public:
            CppEvent1<bool,int> int_event;
            CppEvent2<bool,double,int> double_event;
            CppEvent3<bool,double,int,const char*> triple_event;
            void submit_int()
            {
            int_event.notify(1);
            }
            void submit_double()
            {
            double_event.notify(10.5,100);
            }
            void submit_triple()
            {
            triple_event.notify(10.5,100,"Oh ye");
            }
            };

            Views represented by MyListener1 and MyListener2 are unrelated. The only requirement is for callback (delegate) methods to have parameters signature similar to corresponding CppEvent.

            Collapse Copy Code
            class MyListener1
            {
            public:
            bool update_int(int p)
            {
            Console::WriteLine(S"int update listener 1");
            return true;
            }
            bool update_double(double p,int p1)
            {
            Console::WriteLine(S"double update listener 1");
            return true;
            }
            bool update_triple(double p,int p1,const char* str)
            {
            Console::WriteLine(S"triple update listener 1");
            return true;
            }
            };
            class MyListener2
            {
            public:
            bool fun(int p)
            {
            Console::WriteLine(S"int update listener 2");
            return true;
            }
            };

            The final step is to create viewers MyListener1 and MyListener2 and connect their member functions to corresponding events in MySubject model.

            Collapse Copy Code
            int main(void)
            {
            // create listeners (viewers)
                MyListener1* listener1 = new MyListener1;
            MyListener2* listener2 = new MyListener2;
            // create model
                MySubject subject;
            // connect different viewers to different events of the model
                CppEventHandler h1 = subject.int_event.attach(listener1,
            &MyListener1::update_int);
            CppEventHandler h2 = subject.int_event.attach(listener2,
            &MyListener2::fun);
            CppEventHandler h3 = subject.double_event.attach(listener1,
            &MyListener1::update_double);
            CppEventHandler h4 = subject.triple_event.attach(listener1,
            &MyListener1::update_triple);
            // generate events
                subject.submit_int();
            subject.submit_double();
            subject.submit_triple();
            // detach handlers
                subject.int_event.detach(h1);
            subject.int_event.detach(h2);
            subject.double_event.detach(h3);
            subject.triple_event.detach(h4);
            return 0;
            }

            Resulting output is:

            Collapse Copy Code
            > int update listener 1
            > int update listener 2
            > double update listener 1
            > triple update listener 1

            Implementation

            First of all, if we want to attach different types of event handles (member functions with same types of parameters from different classes) to the same event, we should provide common base for them. We use templates to make it generic for any combination of parameter types in ?delegate? or call back method. There are different event types for every number of arguments in callback function.

            Collapse Copy Code
            // Event handler base for delegate with 1 parameter
            template <typename ReturnT,typename ParamT>
            class EventHandlerBase1
            {
            public:
            virtual ReturnT notify(ParamT param) = 0;
            };

            Specific type of member function pointer within a pointer to the object is stored in the derived class.

            Collapse Copy Code
            template <typename ListenerT,typename ReturnT,typename ParamT>
            class EventHandler1 : public EventHandlerBase1<ReturnT,ParamT>
            {
            typedef ReturnT (ListenerT::*PtrMember)(ParamT);
            ListenerT* m_object;
            PtrMember m_member;
            public:
            EventHandler1(ListenerT* object, PtrMember member)
            : m_object(object), m_member(member)
            {}
            ReturnT notify(ParamT param)
            {
            return (m_object->*m_member)(param);
            }
            };

            Event class stores map of event handlers and notifies all of them when notify method is called. Detach method is used to release handler from the map.

            Collapse Copy Code
            template <typename ReturnT,typename ParamT>
            class CppEvent1
            {
            typedef std::map<int,EventHandlerBase1<ReturnT,ParamT> *> HandlersMap;
            HandlersMap m_handlers;
            int m_count;
            public:
            CppEvent1()
            : m_count(0) {}
            template <typename ListenerT>
            CppEventHandler attach(ListenerT* object,ReturnT (ListenerT::*member)(ParamT))
            {
            typedef ReturnT (ListenerT::*PtrMember)(ParamT);
            m_handlers[m_count] = (new EventHandler1<ListenerT,
            ReturnT,ParamT>(object,member));
            m_count++;
            return m_count-1;
            }
            bool detach(CppEventHandler id)
            {
            HandlersMap::iterator it = m_handlers.find(id);
            if(it == m_handlers.end())
            return false;
            delete it->second;
            m_handlers.erase(it);
            return true;
            }
            ReturnT notify(ParamT param)
            {
            HandlersMap::iterator it = m_handlers.begin();
            for(; it != m_handlers.end(); it++)
            {
            it->second->notify(param);
            }
            return true;
            }
            };

            Comments

            This implementation is quite similar to those in the article ?Emulating C# delegates in Standard C++?. I found out it after I already wrote the article. Actually, the fact that we have a similar way to deal with the problem means that it?s a very intuitive solution for this kind of problem in C++. An advantage of the current implementation is that it supports different number of arguments, so any member function of any class could be a callback (delegate). Probably to have this thing as a part of standard library is a good thing, but even if it?s not a part of the standard, you can use it as it is. This implementation is restricted to events up to 3 parameters, it can be easily extended to other numbers by just rewriting it with different number of parameters (see code for details).

            License

            posted @ 2009-07-22 14:51 yanghaibao| 編輯 收藏
            作用:

            定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。

            UML結構圖:

             

            解析:

            Observer模式定義的是一種一對多的關系,這里的一就是圖中的Subject類,而多則是Obesrver類,當Subject類的狀態發生變化的時候通知與之對應的Obesrver類們也去相應的更新狀態,同時支持動態的添加和刪除Observer對象的功能。Obesrver模式的實現要點是,第一一般subject類都是采用鏈表等容器來存放Observer對象,第二抽取出Observer對象的一些公共的屬性形成Observer基類,而Subject中保存的則是Observer類對象的指針,這樣就使Subject和具體的Observer實現了解耦,也就是Subject不需要去關心到底是哪個Observer對放進了自己的容器中。生活中有很多例子可以看做是Observer模式的運用,比方說,一個班有一個班主任(Subject),他管理手下的一幫學生(Observer),當班里有一些事情發生需要通知學生的時候,班主任要做的不是逐個學生挨個的通知而是把學生召集起來一起通知,實現了班主任和具體學生的關系解耦。

            實現:

            1)Observer.h

            /**//********************************************************************
                created:    2006/07/20
                filename:     Observer.h
                author:        李創
                            http://www.shnenglu.com/converse/

                purpose:    Observer模式的演示代碼
            *********************************************************************/

            #ifndef OBSERVER_H
            #define OBSERVER_H

            #include <list>

            typedef int STATE;

            class Observer;

            // Subject抽象基類,只需要知道Observer基類的聲明就可以了
            class Subject
            {
            public:
                Subject() : m_nSubjectState(-1){}
                virtual ~Subject();

                void Notify();                            // 通知對象改變狀態
                void Attach(Observer *pObserver);        // 新增對象
                void Detach(Observer *pObserver);        // 刪除對象

                // 虛函數,提供默認的實現,派生類可以自己實現來覆蓋基類的實現
                virtual void    SetState(STATE nState);    // 設置狀態
                virtual STATE    GetState();        // 得到狀態

            protected:
                STATE m_nSubjectState;                    // 模擬保存Subject狀態的變量
                std::list<Observer*>    m_ListObserver;    // 保存Observer指針的鏈表
            };

            // Observer抽象基類
            class Observer
            {
            public:
                Observer() : m_nObserverState(-1){}
                virtual ~Observer(){}

                // 純虛函數,各個派生類可能有不同的實現
                // 通知Observer狀態發生了變化
                virtual void Update(Subject* pSubject) = 0;

            protected:
                STATE m_nObserverState;                    // 模擬保存Observer狀態的變量
            };

            // ConcreateSubject類,派生在Subject類
            class ConcreateSubject
                : public Subject
            {
            public:
                ConcreateSubject() : Subject(){}
                virtual ~ConcreateSubject(){}

                // 派生類自己實現來覆蓋基類的實現
                virtual void    SetState(STATE nState);    // 設置狀態
                virtual STATE    GetState();        // 得到狀態

            };

            // ConcreateObserver類派生自Observer
            class ConcreateObserver
                : public Observer
            {
            public:
                ConcreateObserver() : Observer(){}
                virtual ~ConcreateObserver(){}

                // 虛函數,實現基類提供的接口
                virtual void Update(Subject* pSubject);
            };

            #endif

             

            2)Observer.cpp

            /**//********************************************************************
                created:    2006/07/20
                filename:     Observer.cpp
                author:        李創
                            http://www.shnenglu.com/converse/

                purpose:    Observer模式的演示代碼
            *********************************************************************/

            #include "Observer.h"
            #include <iostream>
            #include <algorithm>

            /**//* --------------------------------------------------------------------
            |    Subject類成員函數的實現
            |
             ----------------------------------------------------------------------*/

            void Subject::Attach(Observer *pObserver)
            {
                std::cout << "Attach an Observern";

                m_ListObserver.push_back(pObserver);
            }

            void Subject::Detach(Observer *pObserver)
            {
                std::list<Observer*>::iterator iter;
                iter = std::find(m_ListObserver.begin(), m_ListObserver.end(), pObserver);

                if (m_ListObserver.end() != iter)
                {
                    m_ListObserver.erase(iter);
                }

                std::cout << "Detach an Observern";
            }

            void Subject::Notify()
            {
                std::cout << "Notify Observers''s Staten";

                std::list<Observer*>::iterator iter1, iter2;

                for (iter1 = m_ListObserver.begin(), iter2 = m_ListObserver.end();
                     iter1 != iter2;
                     ++iter1)
                {
                    (*iter1)->Update(this);
                }
            }

            void Subject::SetState(STATE nState)
            {
                std::cout << "SetState By Subjectn";
                m_nSubjectState = nState;
            }

            STATE Subject::GetState()
            {
                std::cout << "GetState By Subjectn";
                return m_nSubjectState;
            }

            Subject::~Subject()
            {
                std::list<Observer*>::iterator iter1, iter2, temp;

                for (iter1 = m_ListObserver.begin(), iter2 = m_ListObserver.end();
                    iter1 != iter2;
                    )
                {
                    temp = iter1;
                    ++iter1;
                    delete (*temp);
                }

                m_ListObserver.clear();
            }

            /**//* --------------------------------------------------------------------
            |    ConcreateSubject類成員函數的實現
            |
            ----------------------------------------------------------------------*/
            void ConcreateSubject::SetState(STATE nState)
            {
                std::cout << "SetState By ConcreateSubjectn";
                m_nSubjectState = nState;
            }

            STATE ConcreateSubject::GetState()
            {
                std::cout << "GetState By ConcreateSubjectn";
                return m_nSubjectState;
            }

            /**//* --------------------------------------------------------------------
            |    ConcreateObserver類成員函數的實現
            |
            ----------------------------------------------------------------------*/
            void ConcreateObserver::Update(Subject* pSubject)
            {
                if (NULL == pSubject)
                    return;

                m_nObserverState = pSubject->GetState();

                std::cout << "The ObeserverState is " << m_nObserverState << std::endl;
            }


            3)Main.cpp

            /**//********************************************************************
                created:    2006/07/21
                filename:     Main.cpp
                author:        李創
                            http://www.shnenglu.com/converse/

                purpose:    Observer模式的測試代碼
            *********************************************************************/

            #include "Observer.h"
            #include <iostream>

            int main()
            {
                Observer *p1 = new ConcreateObserver;
                Observer *p2 = new ConcreateObserver;

                Subject* p = new ConcreateSubject;
                p->Attach(p1);
                p->Attach(p2);
                p->SetState(4);
                p->Notify();

                p->Detach(p1);
                p->SetState(10);
                p->Notify();

                delete p;

                system("pause");

                return 0;
            }

            posted @ 2009-07-22 14:44 yanghaibao| 編輯 收藏
            http://www.codeproject.com/KB/cpp/CppEvents.aspx
            posted @ 2009-07-22 13:50 yanghaibao| 編輯 收藏

            2009年7月21日

            在許多廣泛應用的程序庫,我們會看到類似 #pragma pack(push, 4) 等這樣的標示。因為用戶會任意更改他們的結構成員對齊選項,對于先于這些內容創建的程序庫來說,不能確保一定的內存布局將可能在預先書寫的一些數據訪問模塊上導致錯誤,或者根本不可能實現。

            我在實現一種 C++ 類的實例的序列化工具時,依賴了內存布局。我知道市面上很多“序列化”工具允許更為廣泛的通信用途,但是它們也是用起來最麻煩的,有很多限制條件。我實現的序列化工具用意很明顯,為特定運行模塊提供便捷高效的持久化存儲能力。

            為了提供感性的認識,提供了一個使用這個序列化工具的類型定義。

            class StorageDoc
            : public SerialOwner
            {
            public:
            Serializable(StorageDoc);

            char c;
            int i;
            SerialString str;
            };

            它繼承自 SerialOwner,它聲明了 Serializable,隱含著實現了一些接口,為基類訪問當前類型信息提供幫助。這是較早書寫的一種方案,現在我會改用模板以便在編譯時建立類型信息,不過原理完全一樣。

            現在,StorageDoc 當中的內存布局需要可確定的,但是用戶會選擇不同的結構成員對齊選項,為此需要設定一個結構成員對齊的“子域”,完成這項能力的偽指令是 #pragma pack。

            #pragma pack( [ show ] | [ push | pop ] [, identifier ] , n )

            1)當選用 show,則添加一條警告信息,指示當前編譯域內的對齊屬性
            2)僅僅設置 n,則重寫編譯器選項 /Zp,并影響到此聲明以下的同一個編譯單元內的所有結構定義
            3)push 以及 pop 管理了一組“子域”堆棧,可以不斷加深嵌套
            4)identifier 命名了堆棧上的對齊項,以便在特定需求中彈出合適的項目

            以下是使用的注意事項:

            1)不論何時,#pragma pack() 總是恢復到 /Zp 的預設值,即使處于 push 的“子域”
            2)#pragma pack(push) 未指定對齊值,則不改變
            3)#pragma pack(pop) 可指定對齊值出棧后的設置值,若不指定則按嵌套等級還原,直至 /Zp 預設值

            綜上,#pragma pack(pop) 總是能正確回退到上一個作用域,不管該作用域通過 #pragma pack(n) 聲明或者 #pragma pack(push, n)。而 #pragma pack() 總是取預設值。對于用戶事先指定了一個“子域”,并在其中引入了一個使用 #pragma pack(n) - #pragma pack() 對而非堆棧形式來聲明局部結構成員對齊的頭文件,會使用戶非常困惑。 就是這樣做的。

            當我們為程序庫編譯運行時,有一些類型要求嚴格地遵守內存布局,比如一些硬件允許我們傳入的數據就需要這么做,就可以把它們限定起來:

            #pragma pack(push, 8)

            #include "Chain.h"
            #include "ByteQueue.h"
            #include "SerialOwner.h"
            #include "SerialUser.h"
            #include "SerialString.h"
            #include "SerialStream.h"

            #pragma pack(pop)

            事情再回到序列化上面,用戶會多次嘗試編譯他們的序列化應用模塊,并指望前一次編譯之后運行所產生的文件仍然是可用的,所以還需要在用戶文件當中明確所選用的對齊值,并一旦確定就不再更改:

            #pragma pack(push, 8)
            class StorageDoc
            : public SerialOwner
            {
            public:
            Serializable(StorageDoc);

            char c;
            int i;
            SerialString str;
            };
            #pragma pack(pop)

            并使用它們:

            StorageDoc doc;

            doc.Load(t("doc.bin"));
            std::cout << doc.str.Get() << std::endl;

            doc.str = ss.str();
            std::cout << doc.str.Get() << std::endl;
            doc.Save(t("doc.bin"));

            這就是全部了,但是正如以上提到的,不僅僅在序列化上,和硬件、鏈接庫的通信也可能存在嚴格的內存布局的要求,如果你在項目設計上遭遇這些困惑,那么現在就可以立即動手解決它們。

            如果對本文提到的序列化能力感興趣的話,可以到以下鏈接了解詳情:

            http://code.google.com/p/los-lib/source/browse/

            目錄是:

            svn/trunk/Inc/Los/

            文件分別是:

            _ISerialUser.h
            ByteQueue.h
            Chain.h
            Serialization.h
            SerialOwner.h
            SerialStream.h
            SerialString.h
            SerialUser.h

            不過在本文發布之時,以上文件所處版本沒有針對結構成員對齊選項進行修改,但并不影響閱讀。

            * 補充一(2009-1-18 02:41)

            聯合以及結構的結構成員對齊異常

            class Tick
            {
            static int _StaticID;

            __int64 _StartLI; // __alignof(LARGE_INTEGER) != __alignof(__int64)
            __int64 _CurrentLI;
            __int64 _Frequency;

            int _ID;
            clock_t _Start;
            clock_t _Current;

            bool _Stop;
            bool _HighPerformance;
            ...
            }

            LARGE_INTEGER 是分別對應兩個 32bit 以及一個 64bit 類型的聯合,奇怪的是隨著全局對齊選項的修改,LARGE_INTEGER 類型本身的請求對齊 __alignof(LARGE_INTEGER) 將取聯合的成員的最大者同全局對齊選項的最小值,也就是說,當 /Zp 設置為 2,那么 LARGE_INTEGER 也將僅承諾在 2 字節邊界上對齊,多么不幸啊。當然如果將這個類型納入 #pragma pack 的限定域那就什么問題都沒有了,不管聯合的對齊算法多么的古怪,只要保證不修改所需的對齊值那將總是能獲得確定的內存布局。

            不過正如上面的代碼列出的,我使用了 __int64 代替了 LARGE_INTEGER 的工作,并在請求 Win32 API 的接口上強制指針轉型,使用的時候亦如此,但若訪問聯合成員剛好為 __int64 類型則直接使用便可。這種方式沒有獲得額外的好處,算是一種抗議的行為,并且讓后來的閱讀者有機會了解到這個見不得光的問題。

            _HighPerformance = ::QueryPerformanceFrequency((LARGE_INTEGER*)&_Frequency) != 0;

            當然作為嚴肅的代碼寫作者,也許你將在不止一處使用到 LARGE_INTEGER,為此我也不拒絕使用如下格式:

            #pragma pack(push, 8)
            #include
            #pragma pack(pop)

            它可保證你萬無一失。

            作為對比,FILETIME 有如下定義:

            typedef struct _FILETIME
            {
            DWORD dwLowDateTime;
            DWORD dwHighDateTime;
            } FILETIME;

            且不論它所需的可能的最大結構成員對齊為 4,它也將伴隨著 /Zp 的更改而變動。因此,在不同的選項的影響下:

            __alignof(LARGE_INTEGER) != __alignof(FILETIME) != __alignof(__int64)

            有些人可能要指責會發生這樣的問題純粹是用戶在玩弄“結構成員對齊選項”而導致的,我真希望他能夠讀一讀這篇文章。

            * 補充二(2009-1-18 02:41)

            D3D 與用戶定義結構的協調

            class VertexXYZ_N_T1
            {
            public:
            float x, y, z;
            float normal_x, normal_y, normal_z;
            float u, v;
            DeviceBitmap* bitmap;
            Material* material;
            float temp_val;

            static const int FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
            };

            這是一個自定義頂點結構,它的最大成員字節數為 4,所有的成員也都是 4 字節邊界,不論作何選項,始終保持緊湊存儲,若其中一個成員擴展為 8 字節,那么伴隨著選項的更改,VertexXYZ_N_T1 要求的對齊邊界可導致部分空洞,從而同硬件所需的頂點緩存數據布局存在出入,我不追究硬件是否使用 double 值,但是現在就應當使用

            #pragma pack(push, 4)
            ...
            #pragma pack(pop)

            加以限定。

            我還定義了 Matrix, Material, Vector3, Colorf 等類型,如果要使得這些數據同 D3D, D3DX 的相應類型在內存上兼容的,也是需要限定的。

            posted @ 2009-07-21 12:26 yanghaibao| 編輯 收藏

            本文主要包括二個部分,第一部分重點介紹在VC中,怎么樣采用sizeof來求結構的大小,以及容易出現的問題,并給出解決問題的方法,第二部分總結出VC中sizeof的主要用法。

            1、 sizeof應用在結構上的情況

            請看下面的結構:

            struct MyStruct

            {

            double dda1;

            char dda;

            int type

            };

            對結構MyStruct采用sizeof會出現什么結果呢?sizeof(MyStruct)為多少呢?也許你會這樣求:

            sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13

            但是當在VC中測試上面結構的大小時,你會發現sizeof(MyStruct)為16。你知道為什么在VC中會得出這樣一個結果嗎?

            其實,這是VC對變量存儲的一個特殊處理。為了提高CPU的存儲速度,VC對一些變量的起始地址做了“對齊”處理。在默認情況下,VC規定各成員變量存放的起始地址相對于結構的起始地址的偏移量必須為該變量的類型所占用的字節數的倍數。下面列出常用類型的對齊方式(vc6.0,32位系統)。

            類型
            對齊方式(變量存放的起始地址相對于結構的起始地址的偏移量)

            Char
            偏移量必須為sizeof(char)即1的倍數

            int
            偏移量必須為sizeof(int)即4的倍數

            float
            偏移量必須為sizeof(float)即4的倍數

            double
            偏移量必須為sizeof(double)即8的倍數

            Short
            偏移量必須為sizeof(short)即2的倍數

             

            各成員變量在存放的時候根據在結構中出現的順序依次申請空間,同時按照上面的對齊方式調整位置,空缺的字節VC會自動填充。同時VC為了確保結構的大小為結構的字節邊界數(即該結構中占用最大空間的類型所占用的字節數)的倍數,所以在為最后一個成員變量申請空間后,還會根據需要自動填充空缺的字節。

            下面用前面的例子來說明VC到底怎么樣來存放結構的。

            struct MyStruct

            {

            double dda1;

            char dda;

            int type

            };

            為上面的結構分配空間的時候,VC根據成員變量出現的順序和對齊方式,先為第一個成員dda1分配空間,其起始地址跟結構的起始地址相同(剛好偏移量0剛好為sizeof(double)的倍數),該成員變量占用sizeof(double)=8個字節;接下來為第二個成員dda分配空間,這時下一個可以分配的地址對于結構的起始地址的偏移量為8,是sizeof(char)的倍數,所以把dda存放在偏移量為8的地方滿足對齊方式,該成員變量占用sizeof(char)=1個字節;接下來為第三個成員type分配空間,這時下一個可以分配的地址對于結構的起始地址的偏移量為9,不是sizeof(int)=4的倍數,為了滿足對齊方式對偏移量的約束問題,VC自動填充3個字節(這三個字節沒有放什么東西),這時下一個可以分配的地址對于結構的起始地址的偏移量為12,剛好是sizeof(int)=4的倍數,所以把type存放在偏移量為12的地方,該成員變量占用sizeof(int)=4個字節;這時整個結構的成員變量已經都分配了空間,總的占用的空間大小為:8+1+3+4=16,剛好為結構的字節邊界數(即結構中占用最大空間的類型所占用的字節數sizeof(double)=8)的倍數,所以沒有空缺的字節需要填充。所以整個結構的大小為:sizeof(MyStruct)=8+1+3+4=16,其中有3個字節是VC自動填充的,沒有放任何有意義的東西。

            下面再舉個例子,交換一下上面的MyStruct的成員變量的位置,使它變成下面的情況:

            struct MyStruct

            {

            char dda;

            double dda1;

            int type

            };

            這個結構占用的空間為多大呢?在VC6.0環境下,可以得到sizeof(MyStruc)為24。結合上面提到的分配空間的一些原則,分析下VC怎么樣為上面的結構分配空間的。(簡單說明)

            struct MyStruct

            {

            char dda;//偏移量為0,滿足對齊方式,dda占用1個字節;

            double dda1;//下一個可用的地址的偏移量為1,不是sizeof(double)=8

            //的倍數,需要補足7個字節才能使偏移量變為8(滿足對齊

            //方式),因此VC自動填充7個字節,dda1存放在偏移量為8

            //的地址上,它占用8個字節。

            int type;//下一個可用的地址的偏移量為16,是sizeof(int)=4的倍

            //數,滿足int的對齊方式,所以不需要VC自動填充,type存

            //放在偏移量為16的地址上,它占用4個字節。

            };//所有成員變量都分配了空間,空間總的大小為1+7+8+4=20,不是結構

            //的節邊界數(即結構中占用最大空間的類型所占用的字節數sizeof

            //(double)=8)的倍數,所以需要填充4個字節,以滿足結構的大小為

            //sizeof(double)=8的倍數。

             

            所以該結構總的大小為:sizeof(MyStruc)為1+7+8+4+4=24。其中總的有7+4=11個字節是VC自動填充的,沒有放任何有意義的東西。

             

            VC對結構的存儲的特殊處理確實提高CPU存儲變量的速度,但是有時候也帶來了一些麻煩,我們也屏蔽掉變量默認的對齊方式,自己可以設定變量的對齊方式。

            VC中提供了#pragma pack(n)來設定變量以n字節對齊方式。n字節對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大于等于該變量所占用的字節數,那么偏移量必須滿足默認的對齊方式,第二、如果n小于該變量的類型所占用的字節數,那么偏移量為n的倍數,不用滿足默認的對齊方式。結構的總大小也有個約束條件,分下面兩種情況:如果n大于所有成員變量類型所占用的字節數,那么結構的總大小必須為占用空間最大的變量占用的空間數的倍數;

            否則必須為n的倍數。下面舉例說明其用法。

            #pragma pack(push) //保存對齊狀態

            #pragma pack(4)//設定為4字節對齊

            struct test

            {

            char m1;

            double m4;

            int m3;

            };

            #pragma pack(pop)//恢復對齊狀態

            以上結構的大小為16,下面分析其存儲情況,首先為m1分配空間,其偏移量為0,滿足我們自己設定的對齊方式(4字節對齊),m1占用1個字節。接著開始為m4分配空間,這時其偏移量為1,需要補足3個字節,這樣使偏移量滿足為n=4的倍數(因為sizeof(double)大于n),m4占用8個字節。接著為m3分配空間,這時其偏移量為12,滿足為4的倍數,m3占用4個字節。這時已經為所有成員變量分配了空間,共分配了16個字節,滿足為n的倍數。如果把上面的#pragma pack(4)改為#pragma pack(16),那么我們可以得到結構的大小為24。(請讀者自己分析)

            2、 sizeof用法總結

            在VC中,sizeof有著許多的用法,而且很容易引起一些錯誤。下面根據sizeof后面的參數對sizeof的用法做個總結。

            A. 參數為數據類型或者為一般變量。例如sizeof(int),sizeof(long)等等。這種情況要注意的是不同系統系統或者不同編譯器得到的結果可能是不同的。例如int類型在16位系統中占2個字節,在32位系統中占4個字節。

            B. 參數為數組或指針。下面舉例說明.

            int a[50]; //sizeof(a)=4*50=200; 求數組所占的空間大小

            int *a=new int[50];// sizeof(a)=4; a為一個指針,sizeof(a)是求指針

            //的大小,在32位系統中,當然是占4個字節。

            C. 參數為結構或類。Sizeof應用在類和結構的處理情況是相同的。但有兩點需要注意,第一、結構或者類中的靜態成員不對結構或者類的大小產生影響,因為靜態變量的存儲位置與結構或者類的實例地址無關。

            第二、沒有成員變量的結構或類的大小為1,因為必須保證結構或類的每一

            個實例在內存中都有唯一的地址。

            下面舉例說明,

            Class Test{int a;static double c};//sizeof(Test)=4.

            Test *s;//sizeof(s)=4,s為一個指針。

            Class test1{ };//sizeof(test1)=1;

            D. 參數為其他。下面舉例說明。

            int func(char s[5]);

            {

            cout<< sizeof(s) << endl;
            //數組參數在傳遞的時候系統處理為一個指針,所

            //以sizeof(s)實際上為求指針的大小。

            return 1;

            }

            sizeof(func(“1234”))=4//因為func的返回類型為int,所以相當于

            求sizeof(int).

             

            以上為sizeof的基本用法,在實際的使用中要注意分析VC的分配變量的分配策略,這樣的話可以避免一些錯誤。

            posted @ 2009-07-21 10:56 yanghaibao| 編輯 收藏
            僅列出標題  下一頁

            導航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            常用鏈接

            留言簿

            隨筆分類

            隨筆檔案

            文章檔案

            收藏夾

            Good blogs

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            99久久99这里只有免费的精品| av无码久久久久久不卡网站| 亚洲国产精品综合久久网络| 国产精品久久久久影视不卡| 亚洲一本综合久久| 久久精品国产99国产精偷 | 2021久久精品国产99国产精品| 国产成年无码久久久久毛片| 青青青青久久精品国产h久久精品五福影院1421 | 99精品国产在热久久无毒不卡| 久久久久久久亚洲精品| 品成人欧美大片久久国产欧美... 品成人欧美大片久久国产欧美 | 久久婷婷激情综合色综合俺也去| 久久久久人妻一区二区三区 | 国产成人精品综合久久久久| 四虎影视久久久免费| 久久久久亚洲av无码专区喷水| 久久人人爽人人爽人人AV| 久久国产高清一区二区三区| 久久涩综合| 久久精品国产99久久久古代| 草草久久久无码国产专区| 久久精品国产亚洲AV无码偷窥| 伊人久久成人成综合网222| 999久久久国产精品| 久久久久久久综合日本亚洲| 老司机国内精品久久久久| 蜜臀av性久久久久蜜臀aⅴ | 国产香蕉97碰碰久久人人| 亚洲国产精品婷婷久久| 久久91精品国产91久久户| 国产一级持黄大片99久久| 97精品国产91久久久久久| 成人久久精品一区二区三区| 99re这里只有精品热久久 | 久久久久人妻精品一区三寸蜜桃 | 午夜天堂精品久久久久| 国产精品久久影院| 伊人久久精品线影院| 久久精品18| 久久久久久久久66精品片|