??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品免费网站网,久久精品中文字幕无码绿巨人,久久99国产精一区二区三区http://www.shnenglu.com/guying2008/为C++疯狂zh-cnFri, 09 May 2025 02:34:52 GMTFri, 09 May 2025 02:34:52 GMT60C++ newhttp://www.shnenglu.com/guying2008/archive/2009/08/13/93195.htmlyanghaibaoyanghaibaoThu, 13 Aug 2009 06:47:00 GMThttp://www.shnenglu.com/guying2008/archive/2009/08/13/93195.htmlhttp://www.scs.stanford.edu/~dm/home/papers/c++-new.html

yanghaibao 2009-08-13 14:47 发表评论
]]>
注册公司的步骤和费用 http://www.shnenglu.com/guying2008/archive/2009/08/12/93036.htmlyanghaibaoyanghaibaoWed, 12 Aug 2009 08:33:00 GMThttp://www.shnenglu.com/guying2008/archive/2009/08/12/93036.html
一、选择公司的Ş式:

普通的有限责Q公司Q最低注册资?万元Q需?个或2个以上的股东Q?

?6q?月v新的公司法规定,允许1个股东注册有限责d司,q种Ҏ的有限责d司又U?#8220;一人有限公?#8221;(但公司名UC不会?#8220;一?#8221;字样Q执照上会注?#8220;自然人独?#8221;)Q最低注册资?0万元。如果只有你一个h作ؓ股东Q则选择一人有限公司,最低注册资?0万元Q如果你和朋友、家人合伙投资创业,可选择普通的有限公司Q最低注册资?万元。徏议你准备好注册资?万元?

二、注册公司所需的注册资料:
(1)个h资料Qn份证、法人户口本复印件或L证明、居住地址、电话号码)
(2)注册资金
(3)拟订注册公司名称若干
(4)公司l营范围
(5)U房房证、租赁合?
(6)公司住所
(7)股东名册及股东联pȝ话、联pd址
(8)公司的机构及其生办法、职权、议事规?
(9)公司章程

三、注册公司的步骤Q?

1.核名Q到工商局去领取一?#8220;企业(字号)名称预先核准甌?#8221;Q填写你准备取的公司名称Q由工商局上工商局内部|检索是否有重名Q如果没有重名,可以用这个名Uͼ׃核发一?#8220;企业(字号)名称预先核准通知?#8221;。工商名U核准费?0元,交给工商局?40元可以帮你检?个名字,很多名字重复Q所以一般常见的名字׃用试了,免得花冤枉钱?

2.U房Q?M门的写字楼租一间办公室Q如果你自己有厂房或者办公室也可以,有的地方不允许在居民楼里办公?你要交房U给所U办公室的房?所有权?Q假讑֊公室的房U是1000??一般vU最?个月,6个月的房U是6000元?

3.{订U房合同Q你要与你所U的办公室的房东{֮U房合同,q让房东提供房证的复印件。租房合同打印费5?5元,房证复Cg5?.5元?

4.买租房的印花E:你要到税务局M印花E,按年U金的千分之一的税率购乎ͼ贴在房租合同的首c例如你的每q房U是1.2万元Q那p?2元钱的印qQ后面凡是需要用到房U合同的地方Q都需要是贴了印花E的合同复印件?

5.~写“公司章程”Q可以在工商局|站下蝲“公司章程”的样本,修改一下就可以了。章E的最后由所有股东签名?假设章程打印5?股东2人各2份、工商局1份、银?份、会计师事务所1?Q章E打印费15元、下载公司章E的上网?元?

6.ȝ章: 去街上刻章的地方M个私章,l他们讲L人私?方Ş?。刻章费?0元?

7.C计师事务所领取“银行询征?#8221;Q联pM家会计师事务所Q领取一?#8220;银行询征?#8221;Q必L原gQ会计师事务所盖鲜章。如果你不清楚,可以看报U怸的分cd告,有很多会计师事务所的广告。银行询征函10元?

8.去银行开立公叔R资户Q?所有股东带上自己入股的那一部分钱到银行Q带上公司章E、工商局发的核名通知、法Z表的U章、n份证、用于验资的钱、空白询征函表格Q到银行d立公司帐P你要告诉银行是开验资戗开立好公司帐户后,各个股东按自己出资额向公司帐户中存入相应的钱?银行会发l每个股东缴Ƒ֍、ƈ在询征函上盖银行的章。公叔R资户开戯20元?

注意Q公司法规定Q注册公司时Q投资h(股东)必须~纳额的资本,可以以贷币Ş?也就是h民币)Q也可以以实?如汽车、房产、知识权等)。到银行办的只是货币q一部分Q如果你有实物、房产等作ؓ的,需要到会计师事务所鉴定其h值后再以其实际h值出资,比较ȝQ因此徏议你直接拉K来出资,公司法不你用什么手D|的钱Q自q也好、借的也好Q只要如数缴_资款卛_?

9.办理验资报告Q拿着银行出具的股东缴Ƒ֍、银行盖章后的询征函Q以及公司章E、核名通知、房U合同、房产证复印ӞC计师事务所办理验资报告Q会计师事务师验资报告按注册资本收费?0万元以下注册资金验资?00元?

10.注册公司Q到工商局领取公司讄登记的各U表|包括讄登记甌表、股?发v?名单、董事经理监理情c法Z表登记表、指定代表或委托代理人登记表。注册登记费Q按注册资金的万分之8收取。填好后Q连同核名通知、公司章E、房U合同、房产证复印件、验资报告一起交l工商局。大?个工作日后可领取执照。注册公司手l费300元?

11.凭营业执照,到公安局特行U指定的ȝC,d公章、胦务章。后面步骤中Q均需要用到公章或财务章。公?0元,财务?0元?

12.办理企业l织机构代码证:凭营业执照到技术监督局办理l织机构代码证,费用?0元。办q个证需要半个月Q技术监督局会首先发一个预先受理代码证明文Ӟ凭这个文件就可以办理后面的税务登记证、银行基本户开hl了?

13.去银行开基本P凭营业执照、组l机构代码证Q去银行开立基本帐受最好是在原来办理验资时的那个银行的同一|点d理,否则Q会多收100元的验资帐户费用?开基本户需要填很多表,你最好把能带齐的东西全部带上Q要不然要跑很多,包括营业执照正本原g、n份证、组l机构代码证、公财章、法人章?

开基本hQ还需要购C个密码器(?005q下半年P大多银行都有q个规定)Q今后你的公司开支票、划ƾ时Q都需要用密码器来生成密码。公司基本帐号开戯20元,密码?80元?

14.办理E务登记Q领取执照后Q?0日内到当地税务局甌领取E务登记证。一般的公司都需要办?U税务登记证Q即国税和地E。费用是?0元,?0元?

15.请兼职会计:办理E务登记证时Q必L一个会计,因ؓE务局要求提交的资料其中有一Ҏ会计资格证和w䆾证。你可先请一个兼职会计,公司刚开始请的兼职会计一?00元工资就可以了?

16.甌领购发票Q如果你的公司是销售商品的Q应该到国税ȝ请发,如果是服务性质的公司,则到地税申领发票?开始可先领?00元的发票?

最后就开始营业了?

四、注册公司的费用Q?
1、工商局工商名称核准Q?0?
2、公司办公室房租6个月Q?000?
3、租房合同打印费5?5元,房证复Cg5?.5?
4、租房的印花E?2?
5、下载公司章E的上网?元,公司章程打印?5?
6、刻法hU章20?
7、会计师事务所的银行询征函10?
8、银行开立公叔R资户开戯20?
9、会计师事务所办理验资报告500?
10、工商局注册公司手箋?00元,信息?20?
11、公??20元,财务??0?
12、技术监督局办理l织机构代码?48?
13、银行开立公司基本帐号开戯20元、密码器280?
14、国E税务登记证60元,地税E务登记?0?
15、兼职会计工资,200?
16、申请领购发,500?
合计Q?502.5?
如果不算房租、会计工资、发,则合?802.5元?

注册资本最?万元?

注册登记Ҏ注册资本?.08%(1000万以?,0.04%(1000万以上的过部分)收取

营业E:销售商品的公司Q按所开发票额的4%征收增殖E;提供服务的公司,按所开发票额的5%征收营业E?

所得税Q对企业的纯利润征收18-33%的企业所得税?
利润收入?万元Q含3万元Q以下的E率?8%Q利润收入在3万元以上10万元Q含10万元Q的E率?7%Q?0万元以上的ؓ33%?

五、注册公司的相关说明Q?

1.注册公司会不到半q时_最快需?0天时间。地Z同注册公司的费用也有所不同?

2.要注册一个公司,首先惛_l营什么,怎样l营好,再来注册。要不,注册了也没有用,注册了公司是需要很多成本的Q不是一?#8220;好玩”的事情?

3.注册个体单易办;而注册公司要有章E、合同,要验资,E序挺多的?在投入不是太多时Q还是注册个体ؓ好?

4.前期可行性分析调查,你自p真的考虑一?

5.公司必须建立健全的会计制度,你可能担心自׃会,怎么办?刚开始成立的公司Q业务少Q对会计的工作量也非常小Q你可以请一个兼职会计,每个月到你的公司帮你建帐Q二、三天时间就够了Q给?00-500左右的工资即可?

6.每个??10日按时向E务xE,即没有开展业务不需要缴E,也要q行零申报,否则会被|款的。罚N度超q一?00元。营业执照办理下来后一个月内必d理税务登记。每q?-6月年定时q检营业执照?

7.对企业所得税Q做帐很关键Q如果帐面上你的利润很多Q那E率高。所以,q_的购买设备都要开发票Q你吃饭、坐车的都留v来,可以做ؓ你的企业q作成本?

8.营业E是对营业额征税Q不你赚没有赚钱,只有发生了交易,开了发,p征税Q所得税Q是对利润征E,利润是营业额扣减各U成本后剩余的钱Q只有赚了钱Q才会征所得税?

9.有限责Q公司可以注册分公司?

10.开办费是指企业在筹建期间发生的费用Q包括筹建期人员工资、办公费、培训费、差旅费、印刯、注册登记费以及不计入固定资产和无Ş资购徏成本的汇兑损益和利息支出。筹建期是指企业被批准筹Z日v臛_始生产、经营(包括试生产、试营业Q之日的期间?


yanghaibao 2009-08-12 16:33 发表评论
]]>
[转帖] c++中的explicit关键?/title><link>http://www.shnenglu.com/guying2008/archive/2009/07/24/91053.html</link><dc:creator>yanghaibao</dc:creator><author>yanghaibao</author><pubDate>Fri, 24 Jul 2009 08:49:00 GMT</pubDate><guid>http://www.shnenglu.com/guying2008/archive/2009/07/24/91053.html</guid><description><![CDATA[ c++中的explicit关键字用来修饰类的构造函敎ͼ表明该构造函数是昑ּ的,既然?昑ּ"那么必然有"隐式"Q那么什么是昄而什么又是隐式的呢?<br><br>如果c++cȝ构造函数有一个参敎ͼ那么在编译的时候就会有一个缺省的转换操作Q将该构造函数对应数据类型的数据转换cd象,如下面所C:<br>class MyClass<br>{<br>public:<br>MyClass( int num );<br>}<br>....<br>MyClass obj = 10; //ok,convert int to MyClass<br>在上面的代码中编译器自动整型{换ؓMyClasscd象,实际上等同于下面的操作:<br>MyClass temp(10);<br>MyClass obj = temp;<br>上面的所有的操作x所谓的"隐式转换"?br><br>如果要避免这U自动{换的功能Q我们该怎么做呢Q嘿嘿这是关键字explicit的作用了Q将cȝ构造函数声明ؓ"昄"Q也是在声明构造函数的时候前面添加上explicit卛_Q这样就可以防止q种自动的{换操作,如果我们修改上面的MyClasscȝ构造函Cؓ昄的,那么下面的代码就不能够编译通过了,如下所C:<br>class MyClass<br>{<br>public:<br>explicit MyClass( int num );<br>}<br>....<br>MyClass obj = 10; //err,can't non-explict convert<br><br>class isbn_mismatch:public std::logic_error{<br>public:<br>explicit isbn_missmatch(const std::string &s):std:logic_error(s){}<br>isbn_mismatch(const std::string &s,const std::string &lhs,const std::string &rhs):<br>std::logic_error(s),left(lhs),right(rhs){}<br>const std::string left,right;<br>virtual ~isbn_mismatch() throw(){}<br>};<br><br><br>Sales_item& operator+(const Sales_item &lhs,const Sales_item rhs)<br>{<br>if(!lhs.same_isbn(rhs))<br>   throw isbn_mismatch("isbn missmatch",lhs.book(),rhs.book());<br>Sales_item ret(lhs);<br>ret+rhs;<br>return ret;<br>}<br><br><br>Sales_item item1,item2,sum;<br>while(cin>>item1>>item2)<br>{<br>try{<br>   sun=item1+item2;<br>}catch(const isbn_mismatch &e)<br>{<br>   cerr<<e.what()<<"left isbn is:"<<e.left<<"right isbn is:"<<e.right<<endl;<br>}<br>}<br><br>用于用户自定义类型的构造函?指定它是默认的构造函?不可用于转换构造函?因ؓ构造函数有三种:1拯构造函?转换构造函?一般的构造函?我自q术语^_^)<br>?如果一个类或结构存在多个构造函数时,explicit 修饰的那个构造函数就是默认的<br><br>class isbn_mismatch:public std::logic_error{<br>public:<br>explicit isbn_missmatch(const std::string &s):std:logic_error(s){}<br>isbn_mismatch(const std::string &s,const std::string &lhs,const std::string &rhs):<br>std::logic_error(s),left(lhs),right(rhs){}<br>const std::string left,right;<br>virtual ~isbn_mismatch() throw(){}<br>};<br><br><br>Sales_item& operator+(const Sales_item &lhs,const Sales_item rhs)<br>{<br>if(!lhs.same_isbn(rhs))<br>   throw isbn_mismatch("isbn missmatch",lhs.book(),rhs.book());<br>Sales_item ret(lhs);<br>ret+rhs;<br>return ret;<br>}<br><br><br>Sales_item item1,item2,sum;<br>while(cin>>item1>>item2)<br>{<br>try{<br>   sun=item1+item2;<br>}catch(const isbn_mismatch &e)<br>{<br>   cerr<<e.what()<<"left isbn is:"<<e.left<<"right isbn is:"<<e.right<<endl;<br>}<br>}<br><br> <br><br>q个 《ANSI/ISO C++ Professional Programmer's Handbook 》是q样说的<br><br>explicit Constructors<br>A constructor that takes a single argument is, by default, an implicit conversion operator, which converts its argument to<br>an object of its class (see also Chapter 3, "Operator Overloading"). Examine the following concrete example:<br>class string<br>{<br>private:<br>int size;<br>int capacity;<br>char *buff;<br>public:<br>string();<br>string(int size); // constructor and implicit conversion operator<br>string(const char *); // constructor and implicit conversion operator<br>~string();<br>};<br>Class string has three constructors: a default constructor, a constructor that takes int, and a constructor that<br>constructs a string from const char *. The second constructor is used to create an empty string object with an<br>initial preallocated buffer at the specified size. However, in the case of class string, the automatic conversion is<br>dubious. Converting an int into a string object doesn't make sense, although this is exactly what this constructor does.<br><br>Consider the following:<br>int main()<br>{<br>string s = "hello"; //OK, convert a C-string into a string object<br>int ns = 0;<br>s = 1; // 1 oops, programmer intended to write ns = 1,<br>}<br>In the expression s= 1;, the programmer simply mistyped the name of the variable ns, typing s instead. Normally,<br>the compiler detects the incompatible types and issues an error message. However, before ruling it out, the compiler first<br>searches for a user-defined conversion that allows this expression; indeed, it finds the constructor that takes int.<br>Consequently, the compiler interprets the expression s= 1; as if the programmer had written<br>s = string(1);<br>You might encounter a similar problem when calling a function that takes a string argument. The following example<br>can either be a cryptic coding style or simply a programmer's typographical error. However, due to the implicit<br>conversion constructor of class string, it will pass unnoticed:<br>int f(string s);<br>int main()<br>{<br>f(1); // without a an explicit constructor,<br>//this call is expanded into: f ( string(1) );<br>//was that intentional or merely a programmer's typo?<br>}<br>'In order to avoid such implicit conversions, a constructor that takes one argument needs to be declared explicit:<br>class string<br>{<br>//...<br>public:<br>explicit string(int size); // block implicit conversion<br>string(const char *); //implicit conversion<br>~string();<br>};<br>An explicit constructor does not behave as an implicit conversion operator, which enables the compiler to catch the<br>typographical error this time:<br>int main()<br>{<br>string s = "hello"; //OK, convert a C-string into a string object<br>int ns = 0;<br>s = 1; // compile time error ; this time the compiler catches the typo<br>}<br>Why aren't all constructors automatically declared explicit? Under some conditions, the automatic type conversion is<br>useful and well behaved. A good example of this is the third constructor of string:<br>string(const char *);<br><br>The implicit type conversion of const char * to a string object enables its users to write the following:<br>string s;<br>s = "Hello";<br>The compiler implicitly transforms this into<br>string s;<br>//pseudo C++ code:<br>s = string ("Hello"); //create a temporary and assign it to s<br>On the other hand, if you declare this constructor explicit, you have to use explicit type conversion:<br>class string<br>{<br>//...<br>public:<br>explicit string(const char *);<br>};<br>int main()<br>{<br>string s;<br>s = string("Hello"); //explicit conversion now required<br>return 0;<br>}<br>Extensive amounts of legacy C++ code rely on the implicit conversion of constructors. The C++ Standardization<br>committee was aware of that. In order to not make existing code break, the implicit conversion was retained. However, a<br>new keyword, explicit, was introduced to the languageto enable the programmer to block the implicit conversion<br>when it is undesirable. As a rule, a constructor that can be invoked with a single argument needs to be declared<br>explicit. When the implicit type conversion is intentional and well behaved, the constructor can be used as an<br>implicit conversion operator.<br><br>|上扄讲的最好的_<br><br>C++ ?explicit 关键字的作用<br>?C++ 中, 如果一个类有只有一个参数的构造函敎ͼC++ 允许一U特D的声明cd量的方式。在q种情况下,可以直接一个对应于构造函数参数类型的数据直接赋值给cd量,~译器在~译时会自动q行cd转换Q将对应于构造函数参数类型的数据转换为类的对象?如果在构造函数前加上 explicit 修饰词, 则会止q种自动转换Q在q种情况下,即ɞ对应于构造函数参数类型的数据直接赋值给cd量,~译器也会报错?br><br>下面以具体实例来说明?br><br>建立people.cpp 文gQ然后输入下列内容:<br><br>class People<br>{<br>public:<br>int age;<br>explicit People (int a)<br> {<br>  age=a;<br> }<br>};<br>void foo ( void )<br>{<br> People p1(10);  //方式一<br> People* p_p2=new People(10); //方式?br> People p3=10; //方式?br>}<br>q段 C++ E序定义了一个类 people Q包含一个构造函敎ͼ q个构造函数只包含一个整形参?a Q可用于在构造类时初始化 age 变量?br><br>然后定义了一个函数fooQ在q个函数中我们用三种方式分别创徏了三?0岁的“?#8221;。第一U是最一般的cd量声明方式。第二种方式其实是声明了一个peoplecȝ指针变量Q然后在堆中动态创Z一个people实例Qƈ把这个实例的地址赋值给了p_p2。第三种方式是我们所说的Ҏ方式Qؓ什么说Ҏ呢?我们都知道,C/C++是一U强cd语言Q不同的数据cd是不能随意{换的Q如果要q行cd转换Q必进行显式强制类型{换,而这里,没有q行M昑ּ的{换,直接一个整型数据赋值给了类变量p3?br><br>因此Q可以说Q这里进行了一ơ隐式类型{换,~译器自动将对应于构造函数参数类型的数据转换Z该类的对象,因此方式三经~译器自动{换后和方式一最l的实现方式是一L?br><br>不相信? 耛_Q眼见ؓ实,让我们看看底层的实现方式?br><br>Z更容易比较方式一和方式三的实现方式,我们对上面的代码作一点修改,去除方式二:<br><br>void foo ( void )<br>{<br> People p1(10);  //方式一<br> People p3=10; //方式?br>}<br>去除方式二的原因是方式二是在堆上动态创建类实例Q因此会有一些额外代码媄响分析。修改完成后Q用下列命o~译 people.cpp<br><br>$ gcc -S people.cpp<br><br>"-S"选项是GCC输出汇编代码。命令执行后Q默认生成people.s?关键部分内容如下Q?br><br>.globl _Z3foov<br>.type _Z3foov, @function<br>_Z3foov:<br>.LFB5:<br> pushl %ebp<br>.LCFI2:<br> movl %esp, %ebp<br>.LCFI3:<br> subl $24, %esp<br>.LCFI4:<br> movl $10, 4(%esp)<br> leal -4(%ebp), %eax<br> movl %eax, (%esp)<br> call _ZN6PeopleC1Ei<br> movl $10, 4(%esp)<br> leal -8(%ebp), %eax<br> movl %eax, (%esp)<br> call _ZN6PeopleC1Ei<br> leave<br> ret<br><br>?#8220;.LCFI4” 行后面的东西Q?-4行和5-8行几乎一模一P1-4行即为方式一的汇~代码,5-8即ؓ方式三的汇编代码?l心的你可能发现2?行有所不同Q一个是 -4(%ebp) 而另一个一个是 -8(%ebp) Q这分别为类变量P1和P3的地址?br><br>对于不可随意q行cd转换的强cd语言C/C++来说, q可以说是C++的一个特性。哦Q今天好像不是要说C++的特性,而是要知道explicit关键字的作用Q?br><br>explicit关键字到底是什么作用呢Q?它的作用是止q个Ҏ。如文章一开始而言Q凡是用explicit关键字修饰的构造函敎ͼ~译时就不会q行自动转换Q而会报错?br><br>让我们看看吧Q?修改代码Q?br><br>class People<br>{<br>public:<br>int age;<br>explicit People (int a)<br> {<br>  age=a;<br> }<br>};<br>然后再编译:<br>$ gcc -S people.cpp<br>~译器立马报错:<br>people.cpp: In function ‘void foo()’:<br>people.cpp:23: 错误Q请求从 ‘int’ 转换到非标量cd ‘People’ <div class="h33x9zl" id=div_digg></div> <img src ="http://www.shnenglu.com/guying2008/aggbug/91053.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/guying2008/" target="_blank">yanghaibao</a> 2009-07-24 16:49 <a href="http://www.shnenglu.com/guying2008/archive/2009/07/24/91053.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>观察者模式解?/title><link>http://www.shnenglu.com/guying2008/archive/2009/07/22/90864.html</link><dc:creator>yanghaibao</dc:creator><author>yanghaibao</author><pubDate>Wed, 22 Jul 2009 15:19:00 GMT</pubDate><guid>http://www.shnenglu.com/guying2008/archive/2009/07/22/90864.html</guid><description><![CDATA[软g设计中会到q样的关p:一个对象依赖于另一个对象,必须Ҏ后者的状态更新自q状态,可以把后者称作目标对象,前者称作观察者对象。不但观察者依赖于目标Q当目标的状态改变时也要通知观察者,q就出现了双向的依赖。两个对象互怾赖的后果是它们必M起复用。如果一个目标有多个观察者,那么目标也依赖所有观察者,从而目标对象无法独立复用。如何消除目标和观察者之间的互相依赖呢?观察者模式帮助我们解册个问题?br><br>观察者模式把目标对观察者的依赖q行抽象Q目标只知道自己有若干观察者,但不知道q些观察者具体是谁,可能有多个Q当目标状态改变时只要l这些观察者一个通知Q不必作更多的事情。这L标对观察者的依赖pC抽象和最,而目标对具体观察者的依赖被解除了?br><br>cd如下Q?br><br><img src="http://www.shnenglu.com/WebResource.axd?d=pLXXeGbWF7eXU8SMs2-GFZvUWY2JNH05dFx5YzJhGUYAYJAFEaTEq36NAhTPy7_KekvzDFwt8wvQWdByvJIGWdEq6x2KpKD80&t=632780334567500000" width=1 height=1><img border=0 alt=Observer.JPG src="http://www.shnenglu.com/images/cppblog_com/zliner/Observer.JPG" width=448 height=340><br><br>Subject 对象保存一个Observer引用的列表,当我们让一个ConcreteObserver对象观察Subject对象Ӟ调用后者的Attach()ҎQ将前者的引用加入该列表中。当Subject对象状态改变时Q它调用自n的NotifyҎQ该Ҏ调用列表中每一个Observer?Update()Ҏ。一个ConcreteObserver只要重定义Update()p收到通知Q作为对通知的响应,Update()调用 Subject对象的getStatus()获取数据Q然后更新自w。当不需要l观察时QConcreteObserver对象调用Subject对象的Detach()ҎQ其引用被从列表中移除?br><br>解除目标对具体观察者的依赖以后Q很Ҏ增加新的具体观察者,因ؓ不受依赖的方面就可以自由变化Q而目标也可以独立地复用,因ؓ无所依赖的方面就可以不受影响?br><br>以上主要考虑了一个目标有多个观察者的情况Q我们设法解除了目标对具体观察者的依赖Q具体观察者的U类和数目容易改变。有时候一个观察者观察多个目标也是有意义的,在前面的cd中,观察者对具体目标的依赖仍然存在,因此无法适应目标斚w的变化。怎样抽象q种依赖呢?使观察者只知道若干个目标会向自己发出通知Q而不知道q些目标具体是谁Q可能有多少个;在目标向观察者发送通知Ӟ一个自w的引用作ؓ参数Q然后观察者调用其抽象Ҏ可以获得目标状态。这׃得观察者对目标的依赖是抽象的,观察者对具体目标的依赖被解除了?br><br>cd如下Q?br><br><img border=0 alt=Observer2.JPG src="http://www.shnenglu.com/images/cppblog_com/zliner/Observer2.JPG" width=541 height=442><br><br>参考资料:<br><br>1.《设计模?可复用面向对象Y件的基础?Erich Gamma{著Q李英军{译 机械工业出版C? <img src ="http://www.shnenglu.com/guying2008/aggbug/90864.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/guying2008/" target="_blank">yanghaibao</a> 2009-07-22 23:19 <a href="http://www.shnenglu.com/guying2008/archive/2009/07/22/90864.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++~程实现计算CPU占用?/title><link>http://www.shnenglu.com/guying2008/archive/2009/07/22/90850.html</link><dc:creator>yanghaibao</dc:creator><author>yanghaibao</author><pubDate>Wed, 22 Jul 2009 10:11:00 GMT</pubDate><guid>http://www.shnenglu.com/guying2008/archive/2009/07/22/90850.html</guid><description><![CDATA[起学? <script type=text/javascript><!-- google_ad_client = "pub-7345584400661736"; /* 336x280, 创徏?08-4-7,一L?*/ google_ad_slot = "6079382880"; google_ad_width = 336; google_ad_height = 280; //--> </script> <script type=text/javascript src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"></script> <script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script> <script>google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);</script> <ins style="BORDER-BOTTOM: medium none; POSITION: relative; BORDER-LEFT: medium none; PADDING-BOTTOM: 0pt; MARGIN: 0pt; PADDING-LEFT: 0pt; WIDTH: 336px; PADDING-RIGHT: 0pt; DISPLAY: inline-table; HEIGHT: 280px; VISIBILITY: visible; BORDER-TOP: medium none; BORDER-RIGHT: medium none; PADDING-TOP: 0pt"><ins style="BORDER-BOTTOM: medium none; POSITION: relative; BORDER-LEFT: medium none; PADDING-BOTTOM: 0pt; MARGIN: 0pt; PADDING-LEFT: 0pt; WIDTH: 336px; PADDING-RIGHT: 0pt; DISPLAY: block; HEIGHT: 280px; VISIBILITY: visible; BORDER-TOP: medium none; BORDER-RIGHT: medium none; PADDING-TOP: 0pt"><iframe style="POSITION: absolute; TOP: 0pt; LEFT: 0pt" id=google_ads_frame1 height=280 marginHeight=0 src="http://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-7345584400661736&dt=1248257315881&lmt=1248257308&output=html&slotname=6079382880&correlator=1248257315881&url=http%3A%2F%2Fblog.chinaunix.net%2Fu2%2F67530%2Fshowart_601823.html&cb=1&cd=1&frm=0&ga_vid=2053773672.1248257318&ga_sid=1248257318&ga_hid=1939524883&flash=9.0.124&w=336&h=280&u_h=768&u_w=1024&u_ah=734&u_aw=1024&u_cd=32&u_tz=480&u_his=1&u_nplug=15&u_nmime=47&dtd=M&xpc=zzWxpFM4ja&p=http%3A//blog.chinaunix.net" frameBorder=0 width=336 allowTransparency name=google_ads_frame marginWidth=0 scrolling=no></iframe></ins></ins><!-- q告?-->NT/2000ҎQ?br><br>#include <windows.h><br>#include <conio.h><br>#include <stdio.h><br><br>#define SystemBasicInformation 0<br>#define SystemPerformanceInformation 2<br>#define SystemTimeInformation 3<br><br>#define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 (double)((x).LowPart))<br><br>typedef struct<br>{<br>DWORD dwUnknown1;<br>ULONG uKeMaximumIncrement;<br>ULONG uPageSize;<br>ULONG uMmNumberOfPhysicalPages;<br>ULONG uMmLowestPhysicalPage;<br>ULONG uMmHighestPhysicalPage;<br>ULONG uAllocationGranularity;<br>PVOID pLowestUserAddress;<br>PVOID pMmHighestUserAddress;<br>ULONG uKeActiveProcessors;<br>BYTE bKeNumberProcessors;<br>BYTE bUnknown2;<br>WORD wUnknown3;<br>} SYSTEM_BASIC_INFORMATION;<br><br>typedef struct<br>{<br>LARGE_INTEGER liIdleTime;<br>DWORD dwSpare[76];<br>} SYSTEM_PERFORMANCE_INFORMATION;<br><br>typedef struct<br>{<br>LARGE_INTEGER liKeBootTime;<br>LARGE_INTEGER liKeSystemTime;<br>LARGE_INTEGER liExpTimeZoneBias;<br>ULONG uCurrentTimeZoneId;<br>DWORD dwReserved;<br>} SYSTEM_TIME_INFORMATION;<br><br><br>// ntdll!NtQuerySystemInformation (NT specific!)<br>//<br>// The function copies the system information of the<br>// specified type into a buffer<br>//<br>// NTSYSAPI<br>// NTSTATUS<br>// NTAPI<br>// NtQuerySystemInformation(<br>// IN UINT SystemInformationClass, // information type<br>// OUT PVOID SystemInformation, // pointer to buffer<br>// IN ULONG SystemInformationLength, // buffer size in bytes<br>// OUT PULONG ReturnLength OPTIONAL // pointer to a 32-bit<br>// // variable that receives<br>// // the number of bytes<br>// // written to the buffer <br>// );<br>typedef LONG (WINAPI *PROCNTQSI)(UINT,PVOID,ULONG,PULONG);<br><br>PROCNTQSI NtQuerySystemInformation;<br><br><br>void main(void)<br>{<br>SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;<br>SYSTEM_TIME_INFORMATION SysTimeInfo;<br>SYSTEM_BASIC_INFORMATION SysBaseInfo;<br>double dbIdleTime;<br>double dbSystemTime;<br>LONG status;<br>LARGE_INTEGER liOldIdleTime = {0,0};<br>LARGE_INTEGER liOldSystemTime = {0,0};<br><br>NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(<br>GetModuleHandle("ntdll"),<br>"NtQuerySystemInformation"<br>);<br><br>if (!NtQuerySystemInformation)<br>return;<br><br>// get number of processors in the system<br>status = NtQuerySystemInformation(SystemBasicInformation,&SysBaseInfo,sizeof(SysBaseInfo),NULL);<br>if (status != NO_ERROR)<br>return;<br><br>printf("\nCPU Usage (press any key to exit): ");<br>while(!_kbhit())<br>{<br>// get new system time<br>status = NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);<br>if (status!=NO_ERROR)<br>return;<br><br>// get new CPU's idle time<br>status = NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);<br>if (status != NO_ERROR)<br>return;<br><br><span id="f9fj393" class=sp874>// 本文转自 C Builder研究 - http://www.ccrun.com/article.asp?i=424&d=7jw23a</span><br>// if it's a first call - skip it<br>if (liOldIdleTime.QuadPart != 0)<br>{<br>// CurrentValue = NewValue - OldValue<br>dbIdleTime = Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime);<br>dbSystemTime = Li2Double(SysTimeInfo.liKeSystemTime) - Li2Double(liOldSystemTime);<br><br>// CurrentCpuIdle = IdleTime / SystemTime<br>dbIdleTime = dbIdleTime / dbSystemTime;<br><br>// CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors<br>dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SysBaseInfo.bKeNumberProcessors 0.5;<br><br>printf("\b\b\b\b=%%",(UINT)dbIdleTime);<br>}<br><br>// store new CPU's idle and system time<br>liOldIdleTime = SysPerfInfo.liIdleTime;<br>liOldSystemTime = SysTimeInfo.liKeSystemTime;<br><br>// wait one second<br>Sleep(1000);<br>}<br>printf("\n");<br>}<br><br>//-------------------------------------------------------------<br><br>W9X:<br>#include <windows.h><br>#include <conio.h><br>#include <stdio.h><br><br>void main(void)<br>{<br>HKEY hkey;<br>DWORD dwDataSize;<br>DWORD dwType;<br>DWORD dwCpuUsage;<br><br>// starting the counter<br>if ( RegOpenKeyEx( HKEY_DYN_DATA,<br>"PerfStats\\StartStat",<br>0,KEY_ALL_ACCESS,<br>&hkey ) != ERROR_SUCCESS)<br>return;<br><br>dwDataSize=sizeof(DWORD);<br>RegQueryValueEx( hkey,<br>"KERNEL\\CPUUsage",<br>NULL,&dwType,<br>(LPBYTE)&dwCpuUsage,<br>&dwDataSize );<br><br>RegCloseKey(hkey);<br><br>// geting current counter's value<br>if ( RegOpenKeyEx( HKEY_DYN_DATA,<br>"PerfStats\\StatData",<br>0,KEY_READ,<br>&hkey ) != ERROR_SUCCESS)<br>return;<br><br>printf("\nCPU Usage (press any key to exit): ");<br>while(!_kbhit())<br>{<br>dwDataSize=sizeof(DWORD);<br>RegQueryValueEx( hkey,<br>"KERNEL\\CPUUsage",<br>NULL,&dwType,<br>(LPBYTE)&dwCpuUsage,<br>&dwDataSize );<br>Sleep(500);<br>printf("\b\b\b\b=%%",dwCpuUsage);<br>}<br>printf("\n");<br><br>RegCloseKey(hkey);<br><br>// stoping the counter<br>if ( RegOpenKeyEx( HKEY_DYN_DATA,<br>"PerfStats\\StopStat",<br>0,KEY_ALL_ACCESS,<br>&hkey ) != ERROR_SUCCESS)<br>return;<br><br>dwDataSize=sizeof(DWORD);<br>RegQueryValueEx( hkey,<br>"KERNEL\\CPUUsage",<br>NULL,&dwType,<br>(LPBYTE)&dwCpuUsage,<br>&dwDataSize );<br><br>RegCloseKey(hkey);<br>} <script type=text/javascript><!-- google_ad_client = "pub-7345584400661736"; /* 728x15, 创徏?08-4-7一L容(文字链接Q?*/ google_ad_slot = "6959625474"; google_ad_width = 728; google_ad_height = 15; //--> </script> <script type=text/javascript src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> <script>google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);</script> <ins style="BORDER-BOTTOM: medium none; POSITION: relative; BORDER-LEFT: medium none; PADDING-BOTTOM: 0pt; MARGIN: 0pt; PADDING-LEFT: 0pt; WIDTH: 728px; PADDING-RIGHT: 0pt; DISPLAY: inline-table; HEIGHT: 15px; VISIBILITY: visible; BORDER-TOP: medium none; BORDER-RIGHT: medium none; PADDING-TOP: 0pt"><ins style="BORDER-BOTTOM: medium none; POSITION: relative; BORDER-LEFT: medium none; PADDING-BOTTOM: 0pt; MARGIN: 0pt; PADDING-LEFT: 0pt; WIDTH: 728px; PADDING-RIGHT: 0pt; DISPLAY: block; HEIGHT: 15px; VISIBILITY: visible; BORDER-TOP: medium none; BORDER-RIGHT: medium none; PADDING-TOP: 0pt"><iframe style="POSITION: absolute; TOP: 0pt; LEFT: 0pt" id=google_ads_frame2 height=15 marginHeight=0 src="http://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-7345584400661736&dt=1248257318006&lmt=1248257308&prev_slotnames=6079382880&output=html&slotname=6959625474&correlator=1248257315881&url=http%3A%2F%2Fblog.chinaunix.net%2Fu2%2F67530%2Fshowart_601823.html&cb=1&cd=1&frm=0&ga_vid=2053773672.1248257318&ga_sid=1248257318&ga_hid=1939524883&flash=9.0.124&w=728&h=15&u_h=768&u_w=1024&u_ah=734&u_aw=1024&u_cd=32&u_tz=480&u_his=1&u_nplug=15&u_nmime=47&dtd=4&xpc=ivcWVwcBPa&p=http%3A//blog.chinaunix.net" frameBorder=0 width=728 allowTransparency name=google_ads_frame marginWidth=0 scrolling=no></iframe></ins></ins>NT/2000ҎQ?br><br>#include <windows.h><br>#include <conio.h><br>#include <stdio.h><br><br>#define SystemBasicInformation 0<br>#define SystemPerformanceInformation 2<br>#define SystemTimeInformation 3<br><br>#define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 (double)((x).LowPart))<br><br>typedef struct<br>{<br>DWORD dwUnknown1;<br>ULONG uKeMaximumIncrement;<br>ULONG uPageSize;<br>ULONG uMmNumberOfPhysicalPages;<br>ULONG uMmLowestPhysicalPage;<br>ULONG uMmHighestPhysicalPage;<br>ULONG uAllocationGranularity;<br>PVOID pLowestUserAddress;<br>PVOID pMmHighestUserAddress;<br>ULONG uKeActiveProcessors;<br>BYTE bKeNumberProcessors;<br>BYTE bUnknown2;<br>WORD wUnknown3;<br>} SYSTEM_BASIC_INFORMATION;<br><br>typedef struct<br>{<br>LARGE_INTEGER liIdleTime;<br>DWORD dwSpare[76];<br>} SYSTEM_PERFORMANCE_INFORMATION;<br><br>typedef struct<br>{<br>LARGE_INTEGER liKeBootTime;<br>LARGE_INTEGER liKeSystemTime;<br>LARGE_INTEGER liExpTimeZoneBias;<br>ULONG uCurrentTimeZoneId;<br>DWORD dwReserved;<br>} SYSTEM_TIME_INFORMATION;<br><br><br>// ntdll!NtQuerySystemInformation (NT specific!)<br>//<br>// The function copies the system information of the<br>// specified type into a buffer<br>//<br>// NTSYSAPI<br>// NTSTATUS<br>// NTAPI<br>// NtQuerySystemInformation(<br>// IN UINT SystemInformationClass, // information type<br>// OUT PVOID SystemInformation, // pointer to buffer<br>// IN ULONG SystemInformationLength, // buffer size in bytes<br>// OUT PULONG ReturnLength OPTIONAL // pointer to a 32-bit<br>// // variable that receives<br>// // the number of bytes<br>// // written to the buffer <br>// );<br>typedef LONG (WINAPI *PROCNTQSI)(UINT,PVOID,ULONG,PULONG);<br><br>PROCNTQSI NtQuerySystemInformation;<br><br><br>void main(void)<br>{<br>SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;<br>SYSTEM_TIME_INFORMATION SysTimeInfo;<br>SYSTEM_BASIC_INFORMATION SysBaseInfo;<br>double dbIdleTime;<br>double dbSystemTime;<br>LONG status;<br>LARGE_INTEGER liOldIdleTime = {0,0};<br>LARGE_INTEGER liOldSystemTime = {0,0};<br><br>NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(<br>GetModuleHandle("ntdll"),<br>"NtQuerySystemInformation"<br>);<br><br>if (!NtQuerySystemInformation)<br>return;<br><br>// get number of processors in the system<br>status = NtQuerySystemInformation(SystemBasicInformation,&SysBaseInfo,sizeof(SysBaseInfo),NULL);<br>if (status != NO_ERROR)<br>return;<br><br>printf("\nCPU Usage (press any key to exit): ");<br>while(!_kbhit())<br>{<br>// get new system time<br>status = NtQuerySystemInformation(SystemTimeInformation,&SysTimeInfo,sizeof(SysTimeInfo),0);<br>if (status!=NO_ERROR)<br>return;<br><br>// get new CPU's idle time<br>status = NtQuerySystemInformation(SystemPerformanceInformation,&SysPerfInfo,sizeof(SysPerfInfo),NULL);<br>if (status != NO_ERROR)<br>return;<br><br><span id="9h3rrrj" class=sp874>// 本文转自 C Builder研究 - http://www.ccrun.com/article.asp?i=424&d=7jw23a</span><br>// if it's a first call - skip it<br>if (liOldIdleTime.QuadPart != 0)<br>{<br>// CurrentValue = NewValue - OldValue<br>dbIdleTime = Li2Double(SysPerfInfo.liIdleTime) - Li2Double(liOldIdleTime);<br>dbSystemTime = Li2Double(SysTimeInfo.liKeSystemTime) - Li2Double(liOldSystemTime);<br><br>// CurrentCpuIdle = IdleTime / SystemTime<br>dbIdleTime = dbIdleTime / dbSystemTime;<br><br>// CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors<br>dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SysBaseInfo.bKeNumberProcessors 0.5;<br><br>printf("\b\b\b\b=%%",(UINT)dbIdleTime);<br>}<br><br>// store new CPU's idle and system time<br>liOldIdleTime = SysPerfInfo.liIdleTime;<br>liOldSystemTime = SysTimeInfo.liKeSystemTime;<br><br>// wait one second<br>Sleep(1000);<br>}<br>printf("\n");<br>}<br><br>//-------------------------------------------------------------<br><br>W9X:<br>#include <windows.h><br>#include <conio.h><br>#include <stdio.h><br><br>void main(void)<br>{<br>HKEY hkey;<br>DWORD dwDataSize;<br>DWORD dwType;<br>DWORD dwCpuUsage;<br><br>// starting the counter<br>if ( RegOpenKeyEx( HKEY_DYN_DATA,<br>"PerfStats\\StartStat",<br>0,KEY_ALL_ACCESS,<br>&hkey ) != ERROR_SUCCESS)<br>return;<br><br>dwDataSize=sizeof(DWORD);<br>RegQueryValueEx( hkey,<br>"KERNEL\\CPUUsage",<br>NULL,&dwType,<br>(LPBYTE)&dwCpuUsage,<br>&dwDataSize );<br><br>RegCloseKey(hkey);<br><br>// geting current counter's value<br>if ( RegOpenKeyEx( HKEY_DYN_DATA,<br>"PerfStats\\StatData",<br>0,KEY_READ,<br>&hkey ) != ERROR_SUCCESS)<br>return;<br><br>printf("\nCPU Usage (press any key to exit): ");<br>while(!_kbhit())<br>{<br>dwDataSize=sizeof(DWORD);<br>RegQueryValueEx( hkey,<br>"KERNEL\\CPUUsage",<br>NULL,&dwType,<br>(LPBYTE)&dwCpuUsage,<br>&dwDataSize );<br>Sleep(500);<br>printf("\b\b\b\b=%%",dwCpuUsage);<br>}<br>printf("\n");<br><br>RegCloseKey(hkey);<br><br>// stoping the counter<br>if ( RegOpenKeyEx( HKEY_DYN_DATA,<br>"PerfStats\\StopStat",<br>0,KEY_ALL_ACCESS,<br>&hkey ) != ERROR_SUCCESS)<br>return;<br><br>dwDataSize=sizeof(DWORD);<br>RegQueryValueEx( hkey,<br>"KERNEL\\CPUUsage",<br>NULL,&dwType,<br>(LPBYTE)&dwCpuUsage,<br>&dwDataSize );<br><br>RegCloseKey(hkey);<br>} <img src ="http://www.shnenglu.com/guying2008/aggbug/90850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/guying2008/" target="_blank">yanghaibao</a> 2009-07-22 18:11 <a href="http://www.shnenglu.com/guying2008/archive/2009/07/22/90850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Generic Observer Pattern and Events in C++http://www.shnenglu.com/guying2008/archive/2009/07/22/90831.htmlyanghaibaoyanghaibaoWed, 22 Jul 2009 06:51:00 GMThttp://www.shnenglu.com/guying2008/archive/2009/07/22/90831.htmlIntroduction

One of the interesting features I found in C# is a KEvents and DelegatesK?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 KObserverK?or KDocument/ViewK?design pattern. Classical formulation of it could be found in KDesign Patterns, Elements of Reusable Object Oriented SoftwareK?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 KmodelK?(subject) to be watched by others, called KviewsK?(observers). Each time when information is changed in the KmodelK? KviewsK?attached to the model should receive notification and update there states accordingly to the changed KmodelK?

Classical implementation described in KDesign PatternsK?

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 KsubjectK?and you want to pass different types of parameters to the KviewsK?

One of the examples for complex KModelK?KViewK?relations is a GUI control attached to its processing function. Each time the controlKs 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 KEvents and DelegatesK?concept. The resolution of the problem is easier in C#, because all classes are inherited from the same KobjectK?class.

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

C++ language is powerful enough to express KEventsK?and KDelegatesK?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 KmodelK?

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 KdelegateK?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 KEmulating C# delegates in Standard C++K?/font>. 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 itKs 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 itKs 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



yanghaibao 2009-07-22 14:51 发表评论
]]>
设计模式解析和实?C++) Observer 模式http://www.shnenglu.com/guying2008/archive/2009/07/22/90830.htmlyanghaibaoyanghaibaoWed, 22 Jul 2009 06:44:00 GMThttp://www.shnenglu.com/guying2008/archive/2009/07/22/90830.html作用Q?

定义对象间的一U一对多的依赖关p,当一个对象的状态发生改变时Q所有依赖于它的对象都得到通知q被自动更新?/p>

UMLl构图:

 

解析Q?/p>

Observer模式定义的是一U一对多的关p,q里的一是图中的Subjectc,而多则是Obesrverc,当Subjectcȝ状态发生变化的时候通知与之对应的ObesrvercM也去相应的更新状态,同时支持动态的d和删除Observer对象的功能。Obesrver模式的实现要ҎQ第一一般subjectc都是采用链表等容器来存放Observer对象Q第二抽取出Observer对象的一些公q属性Ş成Observer基类Q而Subject中保存的则是Observercd象的指针Q这样就使Subject和具体的Observer实现了解耦,也就是Subject不需要去兛_到底是哪个ObserverҎq了自己的容器中。生zM有很多例子可以看做是Observer模式的运用,比方_一个班有一个班MQQSubjectQ,他管理手下的一帮学生(ObserverQ,当班里有一些事情发生需要通知学生的时候,班主任要做的不是逐个学生挨个的通知而是把学生召集v来一起通知Q实C班主d具体学生的关p解耦?/p>

实现Q?/p>

1QObserver.h

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

    purpose:    Observer模式的演CZ?br>*********************************************************************/

#ifndef OBSERVER_H
#define OBSERVER_H

#include <list>

typedef int STATE;

class Observer;

// Subject抽象基类,只需要知道Observer基类的声明就可以?br>class Subject
{
public:
    Subject() : m_nSubjectState(-1){}
    virtual ~Subject();

    void Notify();                            // 通知对象改变状?br>    void Attach(Observer *pObserver);        // 新增对象
    void Detach(Observer *pObserver);        // 删除对象

    // 虚函?提供默认的实?zcd以自己实现来覆盖基类的实?br>    virtual void    SetState(STATE nState);    // 讄状?br>    virtual STATE    GetState();        // 得到状?/p>

protected:
    STATE m_nSubjectState;                    // 模拟保存Subject状态的变量
    std::list<Observer*>    m_ListObserver;    // 保存Observer指针的链?br>};

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

    // U虚函数,各个zcd能有不同的实?br>    // 通知Observer状态发生了变化
    virtual void Update(Subject* pSubject) = 0;

protected:
    STATE m_nObserverState;                    // 模拟保存Observer状态的变量
};

// ConcreateSubjectc?z在Subjectc?br>class ConcreateSubject
    : public Subject
{
public:
    ConcreateSubject() : Subject(){}
    virtual ~ConcreateSubject(){}

    // zc自己实现来覆盖基类的实?br>    virtual void    SetState(STATE nState);    // 讄状?br>    virtual STATE    GetState();        // 得到状?/p>

};

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

    // 虚函?实现基类提供的接?br>    virtual void Update(Subject* pSubject);
};

#endif

 

2QObserver.cpp

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

    purpose:    Observer模式的演CZ?br>*********************************************************************/

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

/**//* --------------------------------------------------------------------
|    SubjectcL员函数的实现
|
 ----------------------------------------------------------------------*/

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();
}

/**//* --------------------------------------------------------------------
|    ConcreateSubjectcL员函数的实现
|
----------------------------------------------------------------------*/
void ConcreateSubject::SetState(STATE nState)
{
    std::cout << "SetState By ConcreateSubjectn";
    m_nSubjectState = nState;
}

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

/**//* --------------------------------------------------------------------
|    ConcreateObservercL员函数的实现
|
----------------------------------------------------------------------*/
void ConcreateObserver::Update(Subject* pSubject)
{
    if (NULL == pSubject)
        return;

    m_nObserverState = pSubject->GetState();

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


3QMain.cpp

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

    purpose:    Observer模式的测试代?br>*********************************************************************/

#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;
}



yanghaibao 2009-07-22 14:44 发表评论
]]>
Observer 模式的一U实?/title><link>http://www.shnenglu.com/guying2008/archive/2009/07/22/90824.html</link><dc:creator>yanghaibao</dc:creator><author>yanghaibao</author><pubDate>Wed, 22 Jul 2009 05:50:00 GMT</pubDate><guid>http://www.shnenglu.com/guying2008/archive/2009/07/22/90824.html</guid><description><![CDATA[<a >http://www.codeproject.com/KB/cpp/CppEvents.aspx</a> <img src ="http://www.shnenglu.com/guying2008/aggbug/90824.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/guying2008/" target="_blank">yanghaibao</a> 2009-07-22 13:50 <a href="http://www.shnenglu.com/guying2008/archive/2009/07/22/90824.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转蝲] l构成员寚w与序列化http://www.shnenglu.com/guying2008/archive/2009/07/21/90707.htmlyanghaibaoyanghaibaoTue, 21 Jul 2009 04:26:00 GMThttp://www.shnenglu.com/guying2008/archive/2009/07/21/90707.html

在许多广泛应用的E序库,我们会看到类?#pragma pack(push, 4) {这L标示。因为用户会L更改他们的结构成员对齐选项Q对于先于这些内容创建的E序库来_不能保一定的内存布局可能在预先书写的一些数据访问模块上D错误Q或者根本不可能实现?br>
我在实现一U?C++ cȝ实例的序列化工具Ӟ依赖了内存布局。我知道市面上很?#8220;序列?#8221;工具允许更ؓq泛的通信用途,但是它们也是用v来最ȝ的,有很多限制条件。我实现的序列化工具用意很明显,为特定运行模块提供便捷高效的持久化存储能力?br>
Z提供感性的认识Q提供了一个用这个序列化工具的类型定义?br>
class StorageDoc
: public SerialOwner
{
public:
Serializable(StorageDoc);

char c;
int i;
SerialString str;
};

它承自 SerialOwnerQ它声明?SerializableQ隐含着实现了一些接口,为基c访问当前类型信息提供帮助。这是较早书写的一U方案,现在我会改用模板以便在编译时建立cd信息Q不q原理完全一栗?br>
现在QStorageDoc 当中的内存布局需要可定的,但是用户会选择不同的结构成员对齐选项Qؓ此需要设定一个结构成员对齐的“子域”Q完成这能力的伪指令是 #pragma pack?br>
#pragma pack( [ show ] | [ push | pop ] [, identifier ] , n )

1Q当选用 showQ则d一条警告信息,指示当前~译域内的对齐属?br>2Q仅仅设|?nQ则重写~译器选项 /ZpQƈ影响到此声明以下的同一个编译单元内的所有结构定?br>3Qpush 以及 pop 理了一l?#8220;子域”堆栈Q可以不断加深嵌?br>4Qidentifier 命名了堆栈上的对齐项Q以便在特定需求中弹出合适的目

以下是用的注意事项Q?br>
1Q不ZӞ#pragma pack() L恢复?/Zp 的预讑ր|即处于 push ?#8220;子域”
2Q?pragma pack(push) 未指定对齐|则不改变
3Q?pragma pack(pop) 可指定对齐值出栈后的设||若不指定则按嵌套{q原Q直?/Zp 预设?br>
lgQ?pragma pack(pop) L能正回退C一个作用域Q不该作用域通过 #pragma pack(n) 声明或?#pragma pack(push, n)。?#pragma pack() L取预讑ր{对于用户事先指定了一?#8220;子域”Qƈ在其中引入了一个?#pragma pack(n) - #pragma pack() 对而非堆栈形式来声明局部结构成员对齐的头文Ӟ会用户非常困惑?d3d9types.h> 是q样做的?br>
当我们ؓE序库编译运行时Q有一些类型要求严格地遵守内存布局Q比如一些硬件允许我们传入的数据需要这么做Q就可以把它们限定v来:

#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)

事情再回到序列化上面Q用户会多次试~译他们的序列化应用模块Qƈ指望前一ơ编译之后运行所产生的文件仍然是可用的,所以还需要在用户文g当中明确所选用的对齐|q一旦确定就不再更改Q?br>
#pragma pack(push, 8)
class StorageDoc
: public SerialOwner
{
public:
Serializable(StorageDoc);

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

q用它们:

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"));

q就是全部了Q但是正如以上提到的Q不仅仅在序列化上,和硬件、链接库的通信也可能存在严格的内存布局的要求,如果你在目设计上遭遇这些困惑,那么现在可以立卛_手解军_们?br>
如果Ҏ文提到的序列化能力感兴趣的话Q可以到以下链接了解详情Q?br>
http://code.google.com/p/los-lib/source/browse/

目录是:

svn/trunk/Inc/Los/

文g分别是:

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

不过在本文发布之Ӟ以上文g所处版本没有针对结构成员对齐选项q行修改Q但q不影响阅读?br>
* 补充一Q?009-1-18 02:41Q?br>
联合以及l构的结构成员对齐异?br>
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 cd的联合,奇怪的是随着全局寚w选项的修改,LARGE_INTEGER cd本n的请求对?__alignof(LARGE_INTEGER) 取联合的成员的最大者同全局寚w选项的最|也就是说Q当 /Zp 讄?2Q那?LARGE_INTEGER 也将仅承诺在 2 字节边界上对齐,多么不幸啊。当然如果将q个cdU_ #pragma pack 的限定域那就什么问题都没有了,不管联合的对齐算法多么的古怪,只要保证不修Ҏ需的对齐值那L能获得确定的内存布局?br>
不过正如上面的代码列出的Q我使用?__int64 代替?LARGE_INTEGER 的工作,q在h Win32 API 的接口上强制指针转型Q用的时候亦如此Q但若访问联合成员刚好ؓ __int64 cd则直接用便可。这U方式没有获得额外的好处Q算是一U抗议的行ؓQƈ且让后来的阅读者有Z了解到这个见不得光的问题?br>
_HighPerformance = ::QueryPerformanceFrequency((LARGE_INTEGER*)&_Frequency) != 0;

当然作ؓ严肃的代码写作者,也许你将在不止一处用到 LARGE_INTEGERQؓ此我也不拒绝使用如下格式Q?br>
#pragma pack(push, 8)
#include
#pragma pack(pop)

它可保证你万无一失?br>
作ؓҎQFILETIME 有如下定义:

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

且不论它所需的可能的最大结构成员对齐ؓ 4Q它也将伴随着 /Zp 的更改而变动。因此,在不同的选项的媄响下Q?br>
__alignof(LARGE_INTEGER) != __alignof(FILETIME) != __alignof(__int64)

有些人可能要指责会发生这L问题Ua是用户在玩弄“l构成员寚w选项”而导致的Q我真希望他能够M读这文章?br>
* 补充二(2009-1-18 02:41Q?br>
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;
};

q是一个自定义点l构Q它的最大成员字节数?4Q所有的成员也都?4 字节边界Q不Z何选项Q始l保持紧凑存储,若其中一个成员扩展ؓ 8 字节Q那么伴随着选项的更改,VertexXYZ_N_T1 要求的对齐边界可D部分I洞Q从而同g所需的顶点缓存数据布局存在出入Q我不追I硬件是否?double |但是现在应当?br>
#pragma pack(push, 4)
...
#pragma pack(pop)

加以限定?br>
我还定义?Matrix, Material, Vector3, Colorf {类型,如果要得这些数据同 D3D, D3DX 的相应类型在内存上兼容的Q也是需要限定的?/p>

yanghaibao 2009-07-21 12:26 发表评论
]]>
#pragma pack() 和sizeof http://www.shnenglu.com/guying2008/archive/2009/07/21/90700.htmlyanghaibaoyanghaibaoTue, 21 Jul 2009 02:56:00 GMThttp://www.shnenglu.com/guying2008/archive/2009/07/21/90700.html本文主要包括二个部分Q第一部分重点介绍在VC中,怎么样采用sizeof来求l构的大,以及Ҏ出现的问题,q给决问题的ҎQ第二部分ȝ出VC中sizeof的主要用法?/font>

1?sizeof应用在结构上的情?/font>

L下面的结构:

struct MyStruct

{

double dda1;

char dda;

int type

};

对结构MyStruct采用sizeof会出C么结果呢Qsizeof(MyStruct)为多呢Q也怽会这hQ?/font>

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

但是当在VC中测试上面结构的大小Ӟ你会发现sizeof(MyStruct)?6。你知道Z么在VC中会得出q样一个结果吗Q?/font>

其实Q这是VC对变量存储的一个特D处理。ؓ了提高CPU的存储速度QVC对一些变量的起始地址做了“寚w”处理。在默认情况下,VC规定各成员变量存攄起始地址相对于结构的起始地址的偏U量必须变量的类型所占用的字节数的倍数。下面列出常用类型的寚w方式(vc6.0,32位系l??/font>

cd
寚w方式Q变量存攄起始地址相对于结构的起始地址的偏U量Q?/font>

Char
偏移量必Mؓsizeof(char)?的倍数

int
偏移量必Mؓsizeof(int)?的倍数

float
偏移量必Mؓsizeof(float)?的倍数

double
偏移量必Mؓsizeof(double)?的倍数

Short
偏移量必Mؓsizeof(short)?的倍数

 

各成员变量在存放的时候根据在l构中出现的序依次甌I间Q同时按照上面的寚w方式调整位置Q空~的字节VC会自动填充。同时VCZ保l构的大ؓl构的字节边界数Q即该结构中占用最大空间的cd所占用的字节数Q的倍数Q所以在为最后一个成员变量申L间后Q还会根据需要自动填充空~的字节?/font>

下面用前面的例子来说明VC到底怎么h存放l构的?/font>

struct MyStruct

{

double dda1;

char dda;

int type

}Q?/font>

Z面的l构分配I间的时候,VCҎ成员变量出现的顺序和寚w方式Q先为第一个成员dda1分配I间Q其起始地址跟结构的起始地址相同Q刚好偏U量0刚好为sizeof(double)的倍数Q,该成员变量占用sizeof(double)=8个字节;接下来ؓW二个成员dda分配I间Q这时下一个可以分配的地址对于l构的v始地址的偏U量?Q是sizeof(char)的倍数Q所以把dda存放在偏U量?的地Ҏ_齐方式,该成员变量占用sizeof(char)=1个字节;接下来ؓW三个成员type分配I间Q这时下一个可以分配的地址对于l构的v始地址的偏U量?Q不是sizeof(int)=4的倍数Qؓ了满_齐方式对偏移量的U束问题QVC自动填充3个字节(q三个字节没有放什么东西)Q这时下一个可以分配的地址对于l构的v始地址的偏U量?2Q刚好是sizeof(int)=4的倍数Q所以把type存放在偏U量?2的地方,该成员变量占用sizeof(int)=4个字节;q时整个l构的成员变量已l都分配了空_ȝ占用的空间大ؓQ?+1+3+4=16Q刚好ؓl构的字节边界数Q即l构中占用最大空间的cd所占用的字节数sizeof(double)=8Q的倍数Q所以没有空~的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+3+4=16Q其中有3个字节是VC自动填充的,没有放Q何有意义的东ѝ?/font>

下面再D个例子,交换一下上面的MyStruct的成员变量的位置Q它变成下面的情况Q?/font>

struct MyStruct

{

char dda;

double dda1;

int type

}Q?/font>

q个l构占用的空间ؓ多大呢?在VC6.0环境下,可以得到sizeof(MyStruc)?4。结合上面提到的分配I间的一些原则,分析下VC怎么样ؓ上面的结构分配空间的。(单说明)

struct MyStruct

{

char dda;//偏移量ؓ0Q满_齐方式,dda占用1个字节;

double dda1;//下一个可用的地址的偏U量?Q不是sizeof(double)=8

//的倍数Q需要补?个字节才能偏移量变?Q满_?/font>

//方式Q,因此VC自动填充7个字节,dda1存放在偏U量?

//的地址上,它占?个字节?/font>

int typeQ?/下一个可用的地址的偏U量?6Q是sizeof(int)=4的?/font>

//敎ͼ满int的对齐方式,所以不需要VC自动填充Qtype?/font>

//攑֜偏移量ؓ16的地址上,它占?个字节?/font>

}Q?/所有成员变量都分配了空_I间ȝ大小?+7+8+4=20Q不是结?/font>

//的节边界敎ͼ即结构中占用最大空间的cd所占用的字节数sizeof

//(double)=8Q的倍数Q所以需要填?个字节,以满结构的大小?/font>

//sizeof(double)=8的倍数?/font>

 

所以该l构ȝ大小为:sizeof(MyStruc)?+7+8+4+4=24。其中ȝ?+4=11个字节是VC自动填充的,没有放Q何有意义的东ѝ?/font>

 

VC对结构的存储的特D处理确实提高CPU存储变量的速度Q但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以讑֮变量的对齐方式?/font>

VC中提供了#pragma pack(n)来设定变量以n字节寚w方式。n字节寚w是说变量存攄起始地址的偏U量有两U情况:W一、如果n大于{于该变量所占用的字节数Q那么偏U量必须满默认的对齐方式,W二、如果n于该变量的cd所占用的字节数Q那么偏U量为n的倍数Q不用满默认的寚w方式。结构的d也有个U束条gQ分下面两种情况Q如果n大于所有成员变量类型所占用的字节数Q那么结构的d必Mؓ占用I间最大的变量占用的空间数的倍数Q?/font>

否则必须为n的倍数。下面D例说明其用法?/font>

#pragma pack(push) //保存寚w状?/font>

#pragma pack(4)//讑֮?字节寚w

struct test

{

char m1;

double m4;

int m3;

};

#pragma pack(pop)//恢复寚w状?/font>

以上l构的大ؓ16Q下面分析其存储情况Q首先ؓm1分配I间Q其偏移量ؓ0Q满x们自p定的寚w方式Q?字节寚wQ,m1占用1个字节。接着开始ؓm4分配I间Q这时其偏移量ؓ1Q需要补?个字节,q样使偏U量满为n=4的倍数Q因为sizeof(double)大于nQ?m4占用8个字节。接着为m3分配I间Q这时其偏移量ؓ12Q满ؓ4的倍数Qm3占用4个字节。这时已lؓ所有成员变量分配了I间Q共分配?6个字节,满为n的倍数。如果把上面?pragma pack(4)改ؓ#pragma pack(16)Q那么我们可以得到结构的大小?4。(误者自己分析)

2?sizeof用法ȝ

在VC中,sizeof有着许多的用法,而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个ȝ?/font>

AQ?参数为数据类型或者ؓ一般变量。例如sizeof(int),sizeof(long){等。这U情况要注意的是不同pȝpȝ或者不同编译器得到的结果可能是不同的。例如intcd?6位系l中?个字节,?2位系l中?个字节?/font>

BQ?参数为数l或指针。下面D例说?

int a[50]; //sizeof(a)=4*50=200; 求数l所占的I间大小

int *a=new int[50];// sizeof(a)=4; aZ个指针,sizeof(a)是求指针

//的大??2位系l中Q当然是?个字节?/font>

CQ?参数为结构或cRSizeof应用在类和结构的处理情况是相同的。但有两炚w要注意,W一、结构或者类中的静态成员不对结构或者类的大生媄响,因ؓ静态变量的存储位置与结构或者类的实例地址无关?/font>

W二、没有成员变量的l构或类的大ؓ1Q因为必M证结构或cȝ每一

个实例在内存中都有唯一的地址?/font>

下面举例说明Q?/font>

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

Test *s;//sizeof(s)=4,sZ个指针?/font>

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

DQ?参数为其他。下面D例说明?/font>

int func(char s[5]);

{

cout<< sizeof(s) << endl;
//数组参数在传递的时候系l处理ؓ一个指针,所

//以sizeof(s)实际上ؓ求指针的大小?/font>

return 1;

}

sizeof(func(“1234”))=4//因ؓfunc的返回类型ؓintQ所以相当于

求sizeof(int).

 

以上为sizeof的基本用法,在实际的使用中要注意分析VC的分配变量的分配{略Q这L话可以避免一些错误?/font>



yanghaibao 2009-07-21 10:56 发表评论
]]>
þþƷ| ޾Ʒҹvaþ| ۺպþóAV| þþþƷ鶹 | þþۺϾɫۺ98| 99ƷȾþ޶| þþƷӰԺ| þþþƷ| ƷŮþþþAV| ĻۺϾþò| þþƷ}Ů| ƷȾþþø| 99þ뾫Ʒϵ| þǿdŮ| þùȾƷҰAV| ձƷþ| 鶹Ʒþþһ| һһþaþۺϾƷ| ҹƷþþþþž| ŷþþXXX| ĻƷþ| þþƷ| þþѾƷre6| ޾Ʒ׽þþþþ| ۺϾƷþ| ޳ɫ999þվ| þþƷ˘AV| þˬһ| þAVԴվ| 󽶾þĻ| һձȾþۺ| Ʒtvþþþþþ| Ʒþ㽶߿ۿ| þ99ֻƵƷ8| Ӱ7777þþƷ| þѾƷav| 97þþþ޾Ʒר| 99þþƷһ| þ91˳ɵӰվ| 91þþƷֱ| ˾ҹվھƷþþþþþþ|