??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲一级Av无码毛片久久精品,国内精品伊人久久久久,色综合久久久久综合99http://www.shnenglu.com/zmllegtui/category/8634.htmlNothing in my mind.zh-cnThu, 19 Sep 2013 20:15:50 GMTThu, 19 Sep 2013 20:15:50 GMT60Void and void pointerhttp://www.shnenglu.com/zmllegtui/archive/2009/11/22/101630.htmlzml_cnnkzml_cnnkSun, 22 Nov 2009 08:14:00 GMThttp://www.shnenglu.com/zmllegtui/archive/2009/11/22/101630.htmlhttp://www.shnenglu.com/zmllegtui/comments/101630.htmlhttp://www.shnenglu.com/zmllegtui/archive/2009/11/22/101630.html#Feedback6http://www.shnenglu.com/zmllegtui/comments/commentRss/101630.htmlhttp://www.shnenglu.com/zmllegtui/services/trackbacks/101630.html         
         1.概述

  许多初学者对C/C++语言中的void及void指针cd不甚理解Q因此在使用上出C一些错误。本文将对void关键字的深刻含义q行解说Qƈ详述void及void指针cd的用方法与技巧?br>
  2.void的含?/strong>

  void的字面意思是“无类?#8221;Qvoid *则ؓ“无类型指?#8221;Qvoid *可以指向Mcd的数据?br>
  void几乎只有“注释”和限制程序的作用Q因Z来没有h会定义一个void变量Q让我们试着来定义:

void a;

  q行语句~译时会出错Q提C?#8220;illegal use of type 'void'”。不q,即void a的编译不会出错,它也没有M实际意义?br>
  void真正发挥的作用在于:

  Q?Q对函数q回的限定;

  Q?Q对函数参数的限定?br>
  我们在W三节对以上二点q行具体说明?br>
  众所周知Q如果指针p1和p2的类型相同,那么我们可以直接在p1和p2间互相赋|如果p1和p2指向不同的数据类型,则必M用强制类型{换运符把赋D符双的指针类型{换ؓ左边指针的类型?

  例如Q?br>
float *p1;
int *p2;
p1 = p2;

  其中p1 = p2语句会编译出错,提示“'=' : cannot convert from 'int *' to 'float *'”Q必L为:

p1 = (float *)p2;

  而void *则不同,Mcd的指针都可以直接赋值给它,无需q行强制cd转换Q?

void *p1;
int *p2;
p1 = p2;

  但这q不意味着Qvoid *也可以无需强制cd转换地赋l其它类型的指针。因?#8220;无类?#8221;可以包容“有类?#8221;Q?#8220;有类?#8221;则不能包?#8220;无类?#8221;。道理很单,我们可以?#8220;男h和女人都是h”Q但不能?#8220;人是男h”或?#8220;人是女h”。下面的语句~译出错Q?br>
void *p1;
int *p2;
p2 = p1;

  提示“'=' : cannot convert from 'void *' to 'int *'”?br>
3.void的?br>
  下面l出void关键字的使用规则Q?br>
  规则一如果函数没有q回|那么应声明ؓvoidcd

  在C语言中,凡不加返回值类型限定的函数Q就会被~译器作回整型值处理。但是许多程序员却误以ؓ其ؓvoidcd。例如:

add ( int a, int b )
{
return a + b;
}
int main(int argc, char* argv[])
{
printf ( "2 + 3 = %d", add ( 2, 3) );
}

  E序q行的结果ؓ输出Q?br>
  2 + 3 = 5

  q说明不加返回D明的函数的确为int函数?br>
  林锐博士《高质量C/C++~程》中提到Q?#8220;C++语言有很严格的类型安全检查,不允怸q情况(指函C加类型声明)发生”。可是编译器q不一定这么认定,譬如在Visual C++6.0中上qadd函数的编译无错也无警告且q行正确Q所以不能寄希望于编译器会做严格的类型检查?br>
  因此Qؓ了避免؜乱,我们在编写C/C++E序Ӟ对于M函数都必M个不漏地指定其类型。如果函数没有返回|一定要声明为voidcd。这既是E序良好可读性的需要,也是~程规范性的要求。另外,加上voidcd声明后,也可以发挥代码的“自注?#8221;作用。代码的“自注?#8221;即代码能自己注释自己?br>
  规则二如果函数无参数Q那么应声明其参Cؓvoid

  在C++语言中声明一个这L函数Q?br>
int function(void)
{
return 1;
}

  则进行下面的调用是不合法的:

function(2);

  因ؓ在C++中,函数参数为void的意思是q个函数不接受Q何参数?br>
  我们在Turbo C 2.0中编译:

#include "stdio.h"
fun()
{
return 1;
}
main()
{
printf("%d",fun(2));
getchar();
}

  ~译正确且输?Q这说明Q在C语言中,可以l无参数的函C送Q意类型的参数Q但是在C++~译器中~译同样的代码则会出错。在C++中,不能向无参数的函C送Q何参敎ͼ出错提示“'fun' : function does not take 1 parameters”?br>
  所以,无论在Cq是C++中,若函C接受M参数Q一定要指明参数为void?br>
  规则三小心用void指针cd

  按照ANSI(American National Standards Institute)标准Q不能对void指针q行法操作Q即下列操作都是不合法的Q?br>
void * pvoid;
pvoid++; //ANSIQ错?br>pvoid += 1; //ANSIQ错?br>//ANSI标准之所以这栯定,是因为它坚持Q进行算法操作的指针必须是确定知道其指向数据cd大小的?br>//例如Q?br>int *pint;
pint++; //ANSIQ正?/td>

  pint++的结果是使其增大sizeof(int)?br>
  但是大名鼎鼎的GNU(GNU's Not Unix的羃?则不q么认定Q它指定void *的算法操作与char *一致?br>
  因此下列语句在GNU~译器中皆正:

pvoid++; //GNUQ正?br>pvoid += 1; //GNUQ正?/td>

  pvoid++的执行结果是其增大了1?br>
  在实际的E序设计中,合ANSI标准Qƈ提高E序的可UL性,我们可以q样~写实现同样功能的代码:

void * pvoid;
(char *)pvoid++; //ANSIQ正;GNUQ正?br>(char *)pvoid += 1; //ANSIQ错误;GNUQ正?/td>

  GNU和ANSIq有一些区别,M而言QGNU较ANSI?#8220;开?#8221;Q提供了Ҏ(gu)多语法的支持。但是我们在真实设计Ӟq是应该可能地q合ANSI标准?br>
  规则四如果函数的参数可以是Q意类型指针,那么应声明其参数为void *

  典型的如内存操作函数memcpy和memset的函数原型分别ؓQ?br>
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

  q样QQ何类型的指针都可以传入memcpy和memset中,q也真实CC内存操作函数的意义,因ؓ它操作的对象仅仅是一片内存,而不片内存是什么类型。如果memcpy和memset的参数类型不是void *Q而是char *Q那才叫真的奇怪了Q这Lmemcpy和memset明显不是一?#8220;Ua的,q低񔭑味?#8221;函数Q?br>
  下面的代码执行正:

//CZQmemset接受Lcd指针
int intarray[100];
memset ( intarray, 0, 100*sizeof(int) ); //intarray?
//CZQmemcpy接受Lcd指针
int intarray1[100], intarray2[100];
memcpy ( intarray1, intarray2, 100*sizeof(int) ); //intarray2拯lintarray1

  有趣的是Qmemcpy和memset函数q回的也是void *cdQ标准库函数的编写者是多么地富有学问啊Q?br>
  规则?void不能代表一个真实的变量

  下面代码都企图让void代表一个真实的变量Q因此都是错误的代码Q?br>
void a; //错误
function(void a); //错误

  void体现了一U抽象,q个世界上的变量都是“有类?#8221;的,譬如一个h不是男h是女hQ还有h妖?Q?br>
  void的出现只是ؓ了一U抽象的需要,如果你正地理解了面向对象中“抽象基类”的概念,也很Ҏ(gu)理解void数据cd。正如不能给抽象基类定义一个实例,我们也不能定义一个voidQ让我们cL的称void?#8220;抽象数据cd”Q变量?br>
  4.ȝ

  小的void蕴藏着很丰富的设计哲学Q作Z名程序设计h员,寚w题进行深一个层ơ的思考必然我们受益匪浅


zml_cnnk 2009-11-22 16:14 发表评论
]]>
Type Attribute alignedhttp://www.shnenglu.com/zmllegtui/archive/2009/11/22/101617.htmlzml_cnnkzml_cnnkSun, 22 Nov 2009 06:28:00 GMThttp://www.shnenglu.com/zmllegtui/archive/2009/11/22/101617.htmlhttp://www.shnenglu.com/zmllegtui/comments/101617.htmlhttp://www.shnenglu.com/zmllegtui/archive/2009/11/22/101617.html#Feedback0http://www.shnenglu.com/zmllegtui/comments/commentRss/101617.htmlhttp://www.shnenglu.com/zmllegtui/services/trackbacks/101617.html 

Type attribute aligned allows you to specify the alignment of a structure, class, union, or enumeration. The syntax and considerations for specifying alignment factor are the same as for variable attribute aligned. Like variable attribute aligned, type attribute aligned can only increase alignment. Type attribute packed is used to decrease alignment.

If the attribute appears immediately after the class, struct, union, or enumeration token or immediately after the closing right curly brace, it applies to the type identifier. It can also be specified on a typedef declaration. In a variable declaration, such as

class A {} a;

the placement of the type attribute can be confusing.

In the following definitions, the attribute applies to A:

struct __attribute__((__aligned__(8))) A {};
struct A {} __attribute__((__aligned__(8))) ;
struct __attribute__((__aligned__(8))) A {} a;
struct A {} __attribute__((__aligned__(8))) a;
typedef struct __attribute__((__aligned__(8))) A {} a;
typedef struct A {} __attribute__((__aligned__(8))) a;

In the following definitions, the attribute applies to a:

__attribute__((__aligned__(8))) struct A {} a;
struct A {} const __attribute__((__aligned__(8))) a;
__attribute__((__aligned__(8))) typedef struct A {} a;
typedef __attribute__((__aligned__(8))) struct A {} a;
typedef struct A {} const __attribute__((__aligned__(8))) a;
typedef struct A {} a __attribute__((__aligned__(8)));


zml_cnnk 2009-11-22 14:28 发表评论
]]>
虚函C多态(C++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65386.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:28:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65386.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65386.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65386.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65386.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65386.html</trackback:ping><description><![CDATA[<p>虚函数是C++中用于实现多?polymorphism)的机制。核心理念就是通过基类讉Kzcd义的函数。假设我们有下面的类层次Q?br>class A<br>{<br>public:<br> <wbr> <wbr> <wbr> virtual void foo() { cout << "A::foo() is called" << endl;}<br>};<br>class B: public A<br>{<br>public:<br> <wbr> <wbr> <wbr> virtual void foo() { cout << "B::foo() is called" << endl;}<br>};</p> <p>那么Q在使用的时候,我们可以Q?br>A * a = new B();<br>a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B?</p> <p>q个例子是虚函数的一个典型应用,通过q个例子Q也怽对虚函数有了一些概c它虚就虚在所?#8220;推迟联编”或?#8220;动态联~?#8221;上,一个类函数的调用ƈ不是在编译时刻被定的,而是在运行时刻被定的。由于编写代码的时候ƈ不能定被调用的是基cȝ函数q是哪个zcȝ函数Q所以被成ؓ“?#8221;函数?/p> <p>虚函数只能借助于指针或者引用来辑ֈ多态的效果Q如果是下面q样的代码,则虽然是虚函敎ͼ但它不是多态的Q?br>class A<br>{<br>public:<br> <wbr> <wbr> <wbr> virtual void foo();<br>};<br>class B: public A<br>{<br> <wbr> <wbr> <wbr> virtual void foo();<br>};<br>void bar()<br>{<br> <wbr> <wbr> <wbr> A a;<br> <wbr> <wbr> <wbr> a.foo(); // A::foo()被调?br>}</p> <p> <wbr></p> <p><strong>1.1</strong> <strong>多?/strong></p> <p>在了解了虚函数的意思之后,再考虑什么是多态就很容易了。仍焉对上面的cdơ,但是使用的方法变的复杂了一些:<br>void bar(A *a)<br>{<br> <wbr> <wbr> <wbr> a->foo(); // 被调用的是A::foo() q是B::foo()Q?br>}</p> <p>因ؓfoo()是个虚函敎ͼ所以在barq个函数中,只根据这D代码,无从定q里被调用的是A::foo()q是B::foo()Q但是可以肯定的_如果a指向的是Acȝ实例Q则A::foo()被调用,如果a指向的是Bcȝ实例Q则B::foo()被调用?/p> <p>q种同一代码可以产生不同效果的特点,被称?#8220;多?#8221;?/p> <p> <wbr></p> <p><strong>1.2</strong> <strong>多态有什么用Q?/strong><br>  多态这么神奇,但是能用来做什么呢Q这个命题我难以用一两句话概括,一般的C++教程Q或者其它面向对象语a的教E)都用一个画囄例子来展C多态的用途,我就不再重复q个例子了,如果你不知道q个例子Q随便找本书应该都有介绍。我试图从一个抽象的角度描述一下,回头再结合那个画囄例子Q也怽更Ҏ(gu)理解?/p> <p>在面向对象的~程中,首先会针Ҏ(gu)据进行抽象(定基类Q和l承Q确定派生类Q,构成cdơ。这个类层次的用者在使用它们的时候,如果仍然在需要基cȝ时候写针对基类的代码,在需要派生类的时候写针对zcȝ代码Q就{于cdơ完全暴露在使用者面前。如果这个类层次有Q何的改变Q增加了新类Q,都需要用?#8220;知道”Q针Ҏ(gu)cd代码Q。这样就增加了类层次与其使用者之间的耦合Q有人把q种情况列ؓE序中的“bad smell”之一?/p> <p>多态可以ɽE序员脱这U窘境。再回头看看1.1中的例子Qbar()作ؓA-Bq个cdơ的使用者,它ƈ不知道这个类层次中有多少个类Q每个类都叫什么,但是一样可以很好的工作Q当有一个CcMAcL生出来后Qbar()也不需?#8220;知道”Q修改)。这完全归功于多?-~译器针对虚函数产生了可以在q行时刻定被调用函数的代码?/p> <p> <wbr></p> <p><strong>1.3</strong> <strong>如何</strong><strong>“</strong><strong>动态联~?/strong><strong>”</strong><br>  ~译器是如何针对虚函C生可以再q行时刻定被调用函数的代码呢?也就是说Q虚函数实际上是如何被编译器处理的呢QLippman在深度探索C++对象模型[1]中的不同章节讲到了几U方式,q里?#8220;标准?#8221;方式单介l一下?/p> <p>我所说的“标准”方式Q也是所谓的“VTABLE”机制。编译器发现一个类中有被声明ؓvirtual的函敎ͼ׃为其搞一个虚函数表,也就?VTABLE。VTABLE实际上是一个函数指针的数组Q每个虚函数占用q个数组的一个slot。一个类只有一个VTABLEQ不它有多个实例。派生类有自qVTABLEQ但是派生类的VTABLE与基cȝVTABLE有相同的函数排列序Q同名的虚函数被攑֜两个数组的相同位|上。在创徏cd例的时候,~译器还会在每个实例的内存布局中增加一个vptr字段Q该字段指向本类的VTABLE。通过q些手段Q编译器在看C个虚函数调用的时候,׃这个调用改写,针对1.1中的例子Q?br>void bar(A * a)<br>{<br> <wbr> <wbr> <wbr> a->foo();<br>}<br>会被改写为:<br>void bar(A * a)<br>{<br> <wbr> <wbr> <wbr> (a->vptr[1])();<br>}</p> <p>因ؓzcd基类的foo()函数h相同的VTABLE索引Q而他们的vptr又指向不同的VTABLEQ因此通过q样的方法可以在q行时刻军_调用哪个foo()函数?/p> <p>虽然实际情况q非q么单,但是基本原理大致如此?/p> <p> <wbr></p> <p><strong>1.4 overload</strong><strong>?/strong><strong>override</strong></p> <p>虚函数L在派生类中被改写Q这U改写被UCؓ“override”。我l常h“overload”?#8220;override”q两个单词。但是随着各类C++的书来多Q后来的E序员也怸会再犯我犯过的错误了。但是我打算澄清一下:</p> <p>override是指zc重写基cȝ虚函敎ͼp我们前面BcM重写了AcM的foo()函数。重写的函数必须有一致的参数表和q回|C++标准允许q回g同的情况Q这个我会在“语法”部分单介l,但是很少~译器支持这个featureQ。这个单词好象一直没有什么合适的中文词汇来对应,有h译ؓ“覆盖”Q还贴切一些?br>overloadU定成俗的被译?#8220;重蝲”。是指编写一个与已有函数同名但是参数表不同的函数。例如一个函数即可以接受整型C为参敎ͼ也可以接受QҎ(gu)作ؓ参数?/p> <p> <wbr></p> <p><strong>?/strong><strong>.</strong> <strong>虚函数的语法</strong><br>  虚函数的标志?#8220;virtual”关键字?/p> <p> <wbr></p> <p><strong>2.1</strong> <strong>使用</strong><strong>virtual</strong><strong>关键?/strong></p> <p>考虑下面的类层次Q?br>class A<br>{<br>public:<br> <wbr> <wbr> <wbr> virtual void foo();<br>};<br><br>class B: public A<br>{<br>public:<br> <wbr> <wbr> <wbr> void foo(); // 没有virtual关键?<br>};<br><br>class C: public B // 从Bl承Q不是从Al承Q?br>{<br>public:<br> <wbr> <wbr> <wbr> void foo(); // 也没有virtual关键字!<br>};</p> <p>q种情况下,B::foo()是虚函数QC::foo()也同h虚函数。因此,可以_基类声明的虚函数Q在zcM也是虚函敎ͼ即不再使用virtual关键字?/p> <p> <wbr></p> <p><strong>2.2</strong> <strong>U虚函数</strong><br>  如下声明表示一个函CؓU虚函数Q?br>class A<br>{<br>public:<br> <wbr> <wbr> <wbr> virtual void foo()=0; // =0标志一个虚函数为纯虚函?br>};</p> <p>一个函数声明ؓU虚后,U虚函数的意思是Q我是一个抽象类Q不要把我实例化Q纯虚函数用来规范派生类的行为,实际上就是所谓的“接口”。它告诉使用者,我的zc都会有q个函数?/p> <p> <wbr></p> <p><strong>2.3</strong> <strong>虚析构函?/strong><br>  析构函数也可以是虚的Q甚xU虚的。例如:<br>class A<br>{<br>public:<br>virtual ~A()=0; // U虚析构函数<br>};</p> <p>当一个类打算被用作其它类的基cLQ它的析构函数必L虚的。考虑下面的例子:<br>class A<br>{<br>public:<br> <wbr> <wbr> <wbr> A() { ptra_ = new char[10];}<br> <wbr> <wbr> <wbr> ~A() { delete[] ptra_;} // 非虚析构函数<br>private:<br> <wbr> <wbr> <wbr> char * ptra_;<br>};<br>class B: public A<br>{<br>public:<br> <wbr> <wbr> <wbr> B() { ptrb_ = new char[20];}<br> <wbr> <wbr> <wbr> ~B() { delete[] ptrb_;}<br>private:<br> <wbr> <wbr> <wbr> char * ptrb_;<br>};<br>void foo()<br>{<br> <wbr> <wbr> <wbr> A * a = new B;<br> <wbr> <wbr> <wbr> delete a;<br>}</p> <p>在这个例子中Q程序也怸会象你想象的那样q行Q在执行delete a的时候,实际上只有A::~A()被调用了Q而Bcȝ析构函数q没有被调用Q这是否有点儿可怕?</p> <p>如果上面A::~A()改ؓvirtualQ就可以保证B::~B()也在delete a的时候被调用了。因此基cȝ析构函数都必Lvirtual的?/p> <p>U虚的析构函数ƈ没有什么作用,是虚的就够了。通常只有在希望将一个类变成抽象c(不能实例化的c)Q而这个类又没有合适的函数可以被纯虚化的时候,可以使用U虚的析构函数来辑ֈ目的?/p> <p> <wbr></p> <p><strong>2.4</strong> <strong>虚构造函敎ͼ</strong><br>  构造函C能是虚的?/p> <p> <wbr></p> <p><strong>?/strong><strong>.</strong> <strong>虚函C用技?/strong></p> <p><strong>3.1 private</strong><strong>的虚函数</strong></p> <p>考虑下面的例子:<br>class A<br>{<br>public:<br> <wbr> <wbr> <wbr> void foo() { bar();}<br>private:<br> <wbr> <wbr> <wbr> virtual void bar() { ...}<br>};<br>class B: public A<br>{<br>private:<br> <wbr> <wbr> <wbr> virtual void bar() { ...}<br>};</p> <p>在这个例子中Q虽然bar()在AcM是private的,但是仍然可以出现在派生类中,q仍然可以与public或者protected的虚函数一样生多态的效果。ƈ不会因ؓ它是private的,发生A::foo()不能讉KB::bar()的情况,也不会发生B::bar()对A::bar ()的override不v作用的情c?/p> <p>q种写法的语意是QA告诉BQ你最好override我的bar()函数Q但是你不要它如何使用Q也不要自己调用q个函数?/p> <p> <wbr></p> <p><strong>3.2</strong> <strong>构造函数和析构函数中的虚函数调?/strong></p> <p>一个类的虚函数在它自己的构造函数和析构函数中被调用的时候,它们变成普通函CQ不“?#8221;了。也是说不能在构造函数和析构函数中让自己“多?#8221;。例如:<br>class A<br>{<br>public:<br> <wbr> <wbr> <wbr> A() { foo();} // 在这里,无论如何都是A::foo()被调用!<br> <wbr> <wbr> <wbr> ~A() { foo();} // 同上<br> <wbr> <wbr> <wbr> virtual void foo();<br>};<br>class B: public A<br>{<br>public:<br> <wbr> <wbr> <wbr> virtual void foo();<br>};<br>void bar()<br>{<br> <wbr> <wbr> <wbr> A * a = new B;<br> <wbr> <wbr> <wbr> delete a;<br>}</p> <p>如果你希望delete a的时候,会导致B::foo()被调用,那么你就错了。同P在new B的时候,A的构造函数被调用Q但是在A的构造函CQ被调用的是A::foo()而不是B::foo()?/p> <p> <wbr></p> <p><strong>3.4</strong> <strong>什么时候用虚函数</strong></p> <p>在你设计一个基cȝ时候,如果发现一个函数需要在zc里有不同的表现Q那么它?yu)应该是虚的。从设计的角度讲Q出现在基类中的虚函数是接口Q出现在zcM的虚函数是接口的具体实现。通过q样的方法,可以将对象的行为抽象化?/p> <p>以设计模式[2]中Factory Method模式ZQCreator的factoryMethod()是虚函敎ͼzcoverrideq个函数后,产生不同的Productc,产生的Productc被基类的AnOperation()函数使用。基cȝAnOperation()函数针对Productc进行操作,当然 ProductcM定也有多态(虚函敎ͼ?/p> <p>另外一个例子就是集合操作,假设你有一个以AcMؓ基类的类层次Q又用了一个std:: vector来保存这个类层次中不同类的实例指针,那么你一定希望在对这个集合中的类q行操作的时候,不要把每个指针再cast回到它原来的cdQ派生类Q,而是希望对他们进行同L操作。那么就应该这?#8220;一L操作”声明为virtual?/p> <p>现实中,q不只我丄q两个例子,但是大的原则都是我前面说到的“如果发现一个函数需要在zc里有不同的表现Q那么它?yu)应该是虚?#8221;。这句话也可以反q来_“如果你发现基cL供了虚函敎ͼ那么你最好override?#8221;?/p> <p> <wbr></p> <p><strong>附:</strong><strong>C++</strong><strong>中的虚函数和U虚函数用法</strong></p> <p>1.虚函数和U虚函数可以定义在同一个类(class)中,含有U虚函数的类被称为抽象类Qabstract classQ,而只含有虚函数的c(classQ不能被UCؓ抽象c(abstract classQ?/p> <p>2.虚函数可以被直接使用Q也可以被子c(sub classQ重载以后以多态的形式调用Q而纯虚函数必d子类Qsub classQ中实现该函数才可以使用Q因为纯虚函数在基类Qbase classQ?br>只有声明而没有定义?/p> <p>3.虚函数和U虚函数都可以在子类Qsub classQ中被重载,以多态的形式被调用?/p> <p>4.虚函数和U虚函数通常存在于抽象基c(abstract base class -ABCQ之中,被承的子类重蝲Q目的是提供一个统一的接口?/p> <p>5.虚函数的定义形式Qvirtual {method body} Q纯虚函数的定义形式Qvirtual { } = 0; 在虚函数和纯虚函数的定义中不能有static标识W,原因很简单,被static修饰的函数在~译时候要求前期bind,然而虚函数却是动态绑定(run-time bindQ,而且被两者修饰的函数生命周期Qlife recycleQ也不一栗?/p> <p>6.如果一个类中含有纯虚函敎ͼ那么M试图对该c进行实例化的语句都导致错误的产生Q因为抽象基c(ABCQ是不能被直接调用的。必被子类l承重蝲以后Q根据要求调用其子类的方法?/p> <p>以下Z个简单的虚函数和U虚寒数的用演C,目的是抛砖引玉!<br>//father class<br>class Virtualbase<br>{<br>public:<br> <wbr> <wbr> <wbr> virtual void Demon()= 0; //prue virtual function<br> <wbr> <wbr> <wbr> virtual void Base() {cout<<"this is farther class"<};<br>};<br>//sub class<br>class SubVirtual :public Virtualbase<br>{<br>public:<br> <wbr> <wbr> <wbr> void Demon() { cout<<" this is SubVirtual!"<<endl;}</p> <p>void Base() {cout<<"this is subclass Base"<<endl;}<br>};<br><br>void main()<br>{<br> <wbr> <wbr> <wbr> Virtualbase* inst = new SubVirtual(); //multstate pointer<br> <wbr> <wbr> <wbr> inst->Demon();<br> <wbr> <wbr> <wbr> inst->Base();<br> <wbr> <wbr> <wbr> // inst = new Virtualbase();<br> <wbr> <wbr> <wbr> // inst->Base()<br> <wbr> <wbr> <wbr> return ;<br>}</p> <p>----------------------------------------------------------------------------------------------</p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> 虚函数是在类中被声明为virtual的成员函敎ͼ当编译器看到通过指针或引用调用此cd数时Q对其执行晚l定Q即通过指针Q或引用Q指向的cȝcd信息来决定该函数是哪个类的。通常此类指针或引用都声明为基cȝQ它可以指向基类或派生类的对象。多态指同一个方法根据其所属的不同对象可以有不同的行ؓ?/p> <p>早绑定指~译器在~译期间即知道对象的具体cdq确定此对象调用成员函数的确切地址Q而晚l定是根据指针所指对象的cd信息得到cȝ虚函数表指针q而确定调用成员函数的切地址?/p> <p>~译器对每个包含虚函数的cdZ个表Q称为vtableQ。在vtable中,~译器放|特定类的虚函数地址。在每个带有虚函数的cMQ编译器U密地置一指针Q称为vpointerQ羃写ؓvptrQ,指向q个对象的vtable。通过基类指针做虚函数调用Ӟ也就是做多态调用时Q,~译器静态地插入取得q个vptrQƈvtable表中查找函数地址的代码,q样p调用正确的函C晚捆l发生。ؓ每个c设|vtable、初始化vptr、ؓ虚函数调用插入代码,所有这些都是自动发生的Q所以我们不必担心这些。利用虚函数Q这个对象的合适的函数p被调用,哪怕在~译器还不知道这个对象的特定cd的情况下?/p> <p>在Q何类中不存在昄的类型信息,可对象中必须存放cM息,否则cd不可能在q行时徏立。那q个cM息是什么呢Q我们来看下面几个类Q?/p> <p>class <wbr>no_virtual<br>{<br>public:<br> <wbr> <wbr> <wbr> <wbr>void <wbr>fun1() <wbr>const{}<br> <wbr> <wbr> <wbr> <wbr>int <wbr> <wbr>fun2() <wbr>const <wbr>{ <wbr>return <wbr>a; <wbr>}<br>private:<br> <wbr> <wbr> <wbr> <wbr>int <wbr>a;<br>}</p> <p>class <wbr>one_virtual<br>{<br>public:<br> <wbr> <wbr> <wbr> <wbr>virtual <wbr>void <wbr>fun1() <wbr>const{}<br> <wbr> <wbr> <wbr> <wbr>int <wbr> <wbr>fun2() <wbr>const <wbr>{ <wbr>return <wbr>a; <wbr>}<br>private:<br> <wbr> <wbr> <wbr> <wbr>int <wbr>a;<br>}</p> <p>class <wbr>two_virtual<br>{<br>public:<br> <wbr> <wbr> <wbr> <wbr>virtual <wbr>void <wbr>fun1() <wbr>const{}<br> <wbr> <wbr> <wbr> <wbr>virtual <wbr>int <wbr> <wbr>fun2() <wbr>const <wbr>{ <wbr>return <wbr>a; <wbr>}<br>private:<br> <wbr> <wbr> <wbr> <wbr>int <wbr>a;<br>}</p> <p>以上三个cMQ?br>no_virtual没有虚函敎ͼsizeof(no_virtual)=4Q类no_virtual的长度就是其成员变量整型a的长度;<br>one_virtual有一个虚函数Qsizeof(one_virtual)=8Q?br>two_virtual有两个虚函数Qsizeof(two_virtual)=8Q?nbsp;<wbr>有一个虚函数和两个虚函数的类的长度没有区别,其实它们的长度就是no_virtual的长度加一个void指针的长度,它反映出Q如果有一个或多个虚函敎ͼ~译器在q个l构中插入一个指针( <wbr>vptrQ。在one_virtual <wbr>和two_virtual之间没有区别。这是因为vptr指向一个存攑֜址的表Q只需要一个指针,因ؓ所有虚函数地址都包含在q个表中。这个VPTR可以看作类的类型信息?/p> <p>那我们来看看~译器是怎么建立VPTR指向的这个虚函数表的。先看下面两个类Q?br>class <wbr>base<br>{<br>public:<br> <wbr> <wbr> <wbr> <wbr>void <wbr>bfun(){}<br> <wbr> <wbr> <wbr> <wbr>virtual <wbr>void <wbr>vfun1(){}<br> <wbr> <wbr> <wbr> <wbr>virtual <wbr>int <wbr>vfun2(){}<br>private:<br> <wbr> <wbr> <wbr> <wbr>int <wbr>a;<br>}<br>class <wbr>derived <wbr>: <wbr>public <wbr>base<br>{<br>public:<br> <wbr> <wbr> <wbr> <wbr>void <wbr>dfun(){}<br> <wbr> <wbr> <wbr> <wbr>virtual <wbr>void <wbr>vfun1(){}<br> <wbr> <wbr> <wbr> <wbr>virtual <wbr>int <wbr>vfun3(){}<br>private:<br> <wbr> <wbr> <wbr> <wbr>int <wbr>b;<br>}<br>两个cVPTR指向的虚函数表(VTABLEQ分别如下:<br>basec?br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>—————?br>VPTR—?gt; <wbr>|&base::vfun1 <wbr>|<br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>—————?br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>|&base::vfun2 <wbr>|<br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>—————?br><br>derivedc?br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ——————?br>VPTR—?gt; <wbr>|&derived::vfun1 <wbr>|<br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>——————?br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>|&base::vfun2 <wbr> <wbr> <wbr> <wbr>|<br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>——————?br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>|&derived::vfun3 <wbr>|<br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>——————?/p> <p>每当创徏一个包含有虚函数的cL从包含有虚函数的cL生一个类Ӟ~译器就个类创徏一个VTABLEQ如上图所C。在q个表中Q编译器攄了在q个cM或在它的基类中所有已声明为virtual的函数的地址。如果在q个zcM没有对在基类中声明ؓvirtual的函数进行重新定义,~译器就使用基类的这个虚函数地址。(在derived的VTABLE中,vfun2的入口就是这U情c)然后~译器在q个cM攄VPTR。当使用单承时Q对于每个对象只有一个VPTR。VPTR必须被初始化为指向相应的VTABLEQ这在构造函C发生?/p> <p>一旦VPTR被初始化为指向相应的VTABLEQ对象就"知道"它自己是什么类型。但只有当虚函数被调用时q种自我认知才有用?/p> <p>VPTR常常位于对象的开_~译器能很容易地取到VPTR的|从而确定VTABLE的位|。VPTRL向VTABLE的开始地址Q所有基cd它的子类的虚函数地址Q子c自己定义的虚函数除外)在VTABLE中存储的位置L相同的,如上面basecdderivedcȝVTABLE中vfun1和vfun2的地址L按相同的序存储。编译器知道vfun1位于VPTR处,vfun2位于VPTR+1处,因此在用基类指针调用虚函数时Q编译器首先获取指针指向对象的类型信息(VPTRQ,然后去调用虚函数。如一个basecL针pBase指向了一个derived对象Q那pBase->vfun2()被编译器译?nbsp;<wbr>VPTR+1 <wbr>的调用,因ؓ虚函数vfun2的地址在VTABLE中位于烦引ؓ1的位|上。同理,pBase->vfun3()被编译器译?nbsp;<wbr>VPTR+2的调用。这是所谓的晚绑定?/p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65386.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:28 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65386.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多重l承QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65385.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:27:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65385.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65385.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65385.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65385.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65385.html</trackback:ping><description><![CDATA[转蝲内容。另有其他更好的转蝲参考资料,在博文最末尾?br /><br />    面向对象~程语言中的多重l承指的是一个类别可以同时从多于一个父cȝ承行Z特征的功能。与单一l承相对Q单一l承指一个类别只可以l承自一个父cR? <div> <wbr> <wbr> <wbr> <wbr>重温JavaQ发现Java竟然不支持类多重l承Q直接承类Q,却允许接口的多重l承。?/div> <div> <wbr> <wbr> <wbr> <wbr>C++中类可以多重l承QJava中ؓ什么不实现q个功能呢?多重l承会带来哪些问题,从而导致Java攑ּcȝ多重l承Q?/div> <div> <wbr> <wbr> <wbr> <wbr>再一qQ发现多q以来,多重l承一直是个敏感话题,赞成者看到的是免ȝ拙的混合l承的利处,反对者看到的是多处؜淆的弊端Q例如变量的二义性,q且是多个变量。所以关于它的好处与风险之间孰轻孰重成ؓOO界多q争论的焦点?/div> <div> <wbr> <wbr> <wbr> <wbr>其实最大的问题是出现拓补图Q也是出现ȝ型承结构(DODQ,个h感觉q是个致命伤。正如其名:Diamond of Death?/div> <div> <wbr></div> <div>举个单的例子Q?/div> <div> <wbr> <wbr> <wbr> <wbr>比如一个基c:动物。它有三个派生类Q哺乳类动物Q卡通类动物Q宠物(实都Ş成ISA关系Q。现在有一个子cȝQ从关系上推Q它可以l承自哺乳类Q卡通类Q宠物,都符合ISAQ如果要体现所有的Ҏ(gu),需要全部承,q样Ş成了多重l承Q却也Ş成了DODQ这样以后问题就出现了,从猫到动物的l承有三条\径,如果Z^c,卡通类与宠物类中有相同的成员函数或变量Q这L数据l织方式会Ş成多义?/div> <div> <wbr></div> <div> <wbr> <wbr> <wbr> <wbr>C++怎么解决q个问题的呢Q虚l承。结果就是不得不牺牲一些内存开销Q因Z个功能要在多处被重写。ƈ且函数表里的函数指针必须调整Q这样即使可以满_能,在后期的l护也很复杂?/div> <div> <wbr> <wbr> <wbr> 所以,Java才会采用q样折中的方法,生生的类多重l承题了出去?/div> <div> <wbr> <wbr> <wbr> q且Q网上也有不徏议,要尽可能避免多重l承Q不惜一切代价去避免ȝl构Q以避免后期不可挽回的大q工?/div> <div> <wbr></div> <div> <wbr></div> <div> <wbr> <wbr> <wbr> 多重l承的概念:<span style="color: #ffff00;">C++允许Z个派生类指定多个基类Q这Ll承l构被称做多重?/span><span style="color: #ffff00;">?/span></div> <div> <wbr> <wbr> <wbr> 举个例子Q交通工L可以z出汽车和船连个子c,但拥有汽车和船共同特性水陆两用汽车就必须l承来自汽RcM船类的共同属性?br />  由此我们不难惛_如下的图例与代码Q? <p align="center"><img alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/c/0503/pic/21cppc01.gif" border="0" /></p> <p>当一个派生类要用多重承的时候,必须在派生类名和冒号之后列出所有基cȝcdQƈ用逗好分隔。 </p> <p> <wbr></p> <p>//E序作?宁 <wbr> <wbr> <wbr><br />//站点:www.cndev-lab.com <wbr> <wbr> <wbr><br />//所有稿件均有版?如要转蝲,请务必著名出处和作?nbsp;<wbr> <wbr> <wbr><br /> <wbr><br />#include <wbr><iostream> <wbr><br />using <wbr>namespace <wbr>std; <wbr><br /> <wbr><br />class <wbr>Vehicle <wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Vehicle(int <wbr>weight <wbr>= <wbr>0) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Vehicle::weight <wbr>= <wbr>weight; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>SetWeight(int <wbr>weight) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"重新讄重量"<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Vehicle::weight <wbr>= <wbr>weight; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>virtual <wbr>void <wbr>ShowMe() <wbr>= <wbr>0; <wbr><br /> <wbr> <wbr> <wbr> <wbr>protected: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>int <wbr>weight; <wbr><br />}; <wbr><br />class <wbr>Car:public <wbr>Vehicle//汽R <wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Car(int <wbr>weight=0,int <wbr>aird=0):Vehicle(weight) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Car::aird <wbr>= <wbr>aird; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>ShowMe() <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"我是汽RQ?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr>protected: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>int <wbr>aird; <wbr><br />}; <wbr><br /> <wbr><br />class <wbr>Boat:public <wbr>Vehicle//?nbsp;<wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Boat(int <wbr>weight=0,float <wbr>tonnage=0):Vehicle(weight) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Boat::tonnage <wbr>= <wbr>tonnage; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>ShowMe() <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"我是船!"<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr>protected: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>float <wbr>tonnage; <wbr><br />}; <wbr><br /> <wbr><br />class <wbr>AmphibianCar:public <wbr>Car,public <wbr>Boat//水陆两用汽R,多重l承的体?nbsp;<wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>AmphibianCar(int <wbr>weight,int <wbr>aird,float <wbr>tonnage) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>:<span style="color: #ffff00;">Vehicle(weight)</span>,Car(weight,aird),Boat(weight,tonnage) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>//<span style="color: #ffff00;">多重l承要注意调用基cL造函?nbsp;</span><wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>ShowMe() <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"我是水陆两用汽RQ?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br />}; <wbr><br />int <wbr>main() <wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>AmphibianCar <wbr>a(4,200,1.35f);//错误 <wbr><br /> <wbr> <wbr> <wbr> <wbr>a.SetWeight(3);//错误 <wbr><br /> <wbr> <wbr> <wbr> <wbr>system("pause"); <wbr> <wbr><br />}</p> <p>  上面的代码从表面看,看不出有明显的语法错误,但是它是不能够通过~译的。这有是Z么呢Q?br />  q是׃多重l承带来的承的模糊性带来的问题?/p> <p> <wbr> <wbr> <wbr> 先看如下的图C:</p> <p> <wbr></p> <p align="center"><img alt="" src="http://www.pconline.com.cn/pcedu/empolder/gj/c/0503/pic/21cppc02.gif" border="0" /></p> <p>  在图中深U色标记出来的地Ҏ(gu)是主要问题所在,水陆两用汽Rcȝ承了来自CarcMBoatcȝ属性与Ҏ(gu)QCarcMBoatcd为AmphibianCarcȝ基类Q在内存分配上AmphibianCar获得了来自两个类的SetWeight()成员函数Q当我们调用a.SetWeight(3)的时候计机不知道如何选择分别属于两个基类的被重复拥有了的cL员函数SetWeight()?/p> <p>  ׃q种模糊问题的存在同样也D了AmphibianCar a(4,200,1.35f);执行p|Q系l会产生Vehicle”不是基或成员的错误?/p> <p>  以上面的代码ZQ我们要惌AmphibianCarcL获得一个Vehicle的拷贝,而且又同时共享用CarcMBoatcȝ数据成员与成员函数就必须通过C++所提供?span style="color: #ffff00;">虚拟l承</span>技术来实现?/p> <p>  我们在CarcdBoatcȝ承VehiclecdQ在前面加上virtual关键字就可以实现虚拟l承Q?span style="color: #ffff00;">使用虚拟l承后,当系l碰到多重承的时候就会自动先加入一个Vehicle的拷贝,当再ơ请求一个Vehicle的拷贝的时候就会被忽略Q保证承类成员函数的唯一性?/span><br />  修改后的代码如下Q注意观察变化:</p> <p class="code">//E序作?宁 <wbr> <wbr> <wbr><br />//站点:www.cndev-lab.com <wbr> <wbr> <wbr><br />//所有稿件均有版?如要转蝲,请务必著名出处和作?nbsp;<wbr> <wbr> <wbr><br /> <wbr><br />#include <wbr><iostream> <wbr><br />using <wbr>namespace <wbr>std; <wbr><br /> <wbr><br />class <wbr>Vehicle <wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Vehicle(int <wbr>weight <wbr>= <wbr>0) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Vehicle::weight <wbr>= <wbr>weight; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"载入VehiclecL造函?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>SetWeight(int <wbr>weight) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"重新讄重量"<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Vehicle::weight <wbr>= <wbr>weight; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>virtual <wbr>void <wbr>ShowMe() <wbr>= <wbr>0; <wbr><br /> <wbr> <wbr> <wbr> <wbr>protected: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>int <wbr>weight; <wbr><br />}; <wbr><br />class <wbr>Car:<u>virtual <wbr>public</u> <wbr>Vehicle//汽RQ这里是虚拟l承 <wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Car(int <wbr>weight=0,int <wbr>aird=0):Vehicle(weight) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Car::aird <wbr>= <wbr>aird; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"载入CarcL造函?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>ShowMe() <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"我是汽RQ?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr>protected: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>int <wbr>aird; <wbr><br />}; <wbr><br /> <wbr><br />class <wbr>Boat:<u>virtual <wbr>public</u> <wbr>Vehicle//?q里是虚拟?nbsp;<wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Boat(int <wbr>weight=0,float <wbr>tonnage=0):Vehicle(weight) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>Boat::tonnage <wbr>= <wbr>tonnage; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"载入BoatcL造函?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>ShowMe() <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"我是船!"<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr>protected: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>float <wbr>tonnage; <wbr><br />}; <wbr><br /> <wbr><br />class <wbr>AmphibianCar:public <wbr>Car,public <wbr>Boat//水陆两用汽R,多重l承的体?nbsp;<wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>public: <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>AmphibianCar(int <wbr>weight,int <wbr>aird,float <wbr>tonnage) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>:Vehicle(weight),Car(weight,aird),Boat(weight,tonnage) <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>//多重l承要注意调用基cL造函?nbsp;<wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"载入AmphibianCarcL造函?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>ShowMe() <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"我是水陆两用汽RQ?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>void <wbr>ShowMembers() <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>{ <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>cout<<"重量Q?<<weight<<"吨,"</p> <p class="code"> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <<"I气排量Q?<<aird<<"CCQ?</p> <p class="code"> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <<"排水量:"<<tonnage<<"?<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>} <wbr><br />}; <wbr><br />int <wbr>main() <wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>AmphibianCar <wbr>a(4,200,1.35f); <wbr><br /> <wbr> <wbr> <wbr> <wbr>a.ShowMe(); <wbr><br /> <wbr> <wbr> <wbr> <wbr>a.ShowMembers(); <wbr><br /> <wbr> <wbr> <wbr> <wbr>a.SetWeight(3); <wbr><br /> <wbr> <wbr> <wbr> <wbr>a.ShowMembers(); <wbr><br /> <wbr> <wbr> <wbr> <wbr>system("pause"); <wbr> <wbr><br />}</p> <p>  注意观察cL造函数的构造顺序?br /><strong>  </strong>虽然说虚拟承与虚函数有一定相似的地方Q但读者务必要CQ他们之间是l对没有M联系的!</p> <p>================================================================== <wbr></p> <p>补充Q?/p> <p>1?nbsp;<wbr>当一个类有多个父cLQ每个父cd内存中依ơ排列,然后该类自己的成员?br />2?nbsp;<wbr>每一个父cȝ镜像中,都包含有独立的虚函数?br />3?nbsp;<wbr>当把子类的指针Upcast的时候,两种Upcast的方式得到的l果分别指向各自的父c镜?br />4?nbsp;<wbr>当两个父c重载的虚函C同时Q会使用Thunk机制Q也是_虚函数表中的函数指针q不指向实际的虚函数Q而是指向一段代码。在q一段代码中,会修改This指针QECX寄存器)Q之指向合适的父类镜像Q然后再跌{到实际的虚函C?br />5?nbsp;<wbr>当不使用虚承时Q共同基cȝ成员对象Q在子类中会有独立两分(从两个父cd自承了一份)?br />6?nbsp;<wbr>当用虚l承Ӟ共同基类的成员对象也会在虚函数表中记录,讉K它必d查找虚函数表?br /><br />普通多重承下的虚函数表:<br /><a >http://blog.csdn.net/tangaowen/article/details/5830803<br /></a><a >http://www.cnblogs.com/itech/archive/2009/02/28/1399995.html<br /></a>虚承下的虚函数表:<br /><a >http://www.cnblogs.com/itech/archive/2009/02/27/1399996.html</a><a ><br /></a></p> </div><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65385.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:27 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65385.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字节序(C++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65384.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:27:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65384.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65384.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65384.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65384.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65384.html</trackback:ping><description><![CDATA[ 谈到字节序的问题Q必然牵涉到两大CPUz。那是Motorola的PowerPCpdCPU和Intel的x86pdCPU。PowerPCpd采用big endian方式存储数据Q而x86pd则采用little endian方式存储数据。那么究竟什么是big endianQ什么又是little endian呢? 字节序是指占内存多于一个字节类型的数据在内存中的存N序,通常有小端、大端两U字节顺序。小端字节序指低字节数据存放在内存低地址处,高字节数据存攑֜内存高地址处;大端字节序是高字节数据存攑֜低地址处,低字节数据存攑֜高地址处。基于X86q_的PC机是端字节序的Q而有的嵌入式q_则是大端字节序的。因而对int、uint16、uint32{多?字节cd的数据,在这些嵌入式q_上应该变换其存储序。通常我们认ؓQ在IZ传输的字节的序即网l字节序为标准顺序,考虑C协议的一致以及与同类其它q_产品的互通,在程序中发数据包Ӟ主机字节序转换为网l字节序Q收数据包处网l字节序转换Z机字节序? 其实big endian是指低地址存放最高有效字节(MSBQ,而little endian则是低地址存放最低有效字节(LSBQ?#160; 用文字说明可能比较抽象,下面用图像加以说明。比如数?x12345678在两U不同字节序CPU中的存储序如下所C:对于0x12345678Q? <p>Big endianQ低------->高:12 34 56 78</p> <p>Little endianQ低------->高:78 56 34 12</p> <p> <wbr> <wbr> <wbr> Z么要注意字节序的问题呢?你可能这么问。当Ӟ如果你写的程序只在单机环境下面运行,q且不和别h的程序打交道Q那么你完全可以忽略字节序的存在。但是,如果你的E序要跟别h的程序生交互呢Q在q里我想说说两种语言。C/C++语言~写的程序里数据存储序是跟~译q_所在的CPU相关的,而JAVA~写的程序则唯一采用big endian方式来存储数据。试惻I如果你用C/C++语言在x86q_下编写的E序跟别人的JAVAE序互通时会生什么结果?拿上面?x12345678来说Q你的程序传递给别h的一个数据,指?x12345678的指针传l了JAVAE序Q由于JAVA采取big endian方式存储数据Q很自然的它会将你的数据译?x78563412。什么?竟然变成另外一个数字了Q是的,是q种后果。因此,在你的CE序传给JAVAE序之前有必要进行字节序的{换工作?br> <wbr> <wbr> <wbr> 所有网l协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式UC为网l字节序。当两台采用不同字节序的L通信Ӟ在发送数据之前都必须l过字节序的转换成ؓ|络字节序后再进行传输?/p> <p> <wbr> <wbr> <wbr> 判断端q是大端规则的方法:</p> <p> <wbr>int x = 1;<br> <wbr>if(*(char *)&x == 1)//取x指针强制转换为char*cd再取|此时取到的值是int最低字节?br> <wbr> <wbr> <wbr> <wbr> printf("little-endian\n");<br> <wbr>else<br> <wbr> <wbr> <wbr> <wbr> printf("big-endian\n");</p> <p> <wbr></p> <p> <wbr> <wbr> <wbr> <wbr> 另外补充Q?/p> <p>1QBIG-ENDIAN、LITTLE-ENDIAN、跟CPU有关的,每一UCPU不是BIG-ENDIAN是LITTLE-ENDIAN。网l字节序是指数据在网l上传输时是大头q是头的,在Internet的网l字节序是BIG-ENDIAN。所谓的JAVA字节序指的是在JAVA虚拟Z多字节类型数据的存放序QJAVA字节序也是BIG-ENDIAN?/p> <p>2Q所以在用C/C++写通信E序Ӟ在发送数据前务必用htonl和htonsL整型和短整型的数据进行从L字节序到|络字节序的转换Q而接收数据后对于整型和短整型数据则必调用ntohl和ntohs实现从网l字节序C机字节序的{换。如果通信的一Ҏ(gu)JAVAE序、一Ҏ(gu)C/C++E序Ӟ则需要在C/C++一侧用以上几个方法进行字节序的{换,而JAVA一侧,则不需要做M处理Q因为JAVA字节序与|络字节序都是BIG-ENDIANQ只要C/C++一侧能正确q行转换卛_Q发送前从主机序到网l序Q接收时反变换)。如果通信的双斚w是JAVAQ则Ҏ(gu)不用考虑字节序的问题了?/p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65384.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:27 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65384.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>拯构造函数和赋D符重蝲QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65382.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:26:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65382.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65382.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65382.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65382.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65382.html</trackback:ping><description><![CDATA[<p>以下讨论中将用到的例?</p> <p>class CExample<br />{<br />public:<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample(){pBuffer=NULL; nSize=0;}<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ~CExample(){delete pBuffer;}<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> void Init(int n){ pBuffer=new char[n]; nSize=n;}<br />private:<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> char *pBuffer; //cȝ对象中包含指?指向动态分配的内存资源<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> int nSize;<br />}; </p><p><wbr></p> <p>q个cȝ主要特点是包含指向其他资源的指针?pBuffer指向堆中分配的一D内存空间?nbsp;</p><p><wbr></p> <p>一、拷贝构造函?/p> <p>int main(int argc, char* argv[])<br />{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample theObjone;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> theObjone.Init(40);<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> //现在需要另一个对?需要将他初始化为theObjone的状?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample theObjtwo=theObjone;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ...<br />} </p><p><wbr></p> <p> <wbr> <wbr> <wbr> 语句"CExample theObjtwo=theObjone;"<strong style="color: #ffff00;">用theObjone初始化theObjtwo</strong>。其完成方式是内存拷贝,复制所有成员的倹{完成后QtheObjtwo.pBuffer==theObjone.pBuffer。即它们指向同L地方Q指针虽然复制了Q但所指向的空间ƈ没有复制Q而是׃个对象共用了。这样不W合要求Q对象之间不独立了,qؓI间的删除带来隐(zhn)。所以需要采用必要的手段来避免此cLc?/p> <p> <wbr> <wbr> <wbr> 回顾一下此语句的具体过E?首先建立对象theObjtwoQƈ调用其构造函敎ͼ然后成员被拷贝。可以在构造函Cd操作来解x针成员的问题。所以C++语法中除了提供缺省Ş式的构造函数外Q还规范了另一U特D的构造函敎ͼ拯构造函数?/p> <p> <wbr> <wbr> <wbr> 上面的语句中Q如果类中定义了拯构造函敎ͼq对象徏立时Q调用的是拯构造函敎ͼ在拷贝构造函CQ可以根据传入的变量Q复制指针所指向的资源?/p> <p> <wbr> <wbr> <wbr> 拯构造函数的格式?构造函数名(对象的引?</p> <p> <wbr> <wbr> <wbr> 提供了拷贝构造函数后的CExamplecd义ؓ:</p> <p>class CExample<br />{<br />public:<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample(){pBuffer=NULL; nSize=0;}<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ~CExample(){delete pBuffer;}<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample(const CExample&); //拯构造函?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> void Init(int n){ pBuffer=new char[n]; nSize=n;}<br />private:<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> char *pBuffer; //cȝ对象中包含指?指向动态分配的内存资源<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> int nSize;<br />};</p> <p>CExample::CExample(const CExample& RightSides) //拯构造函数的定义<br />{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> nSize=RightSides.nSize; //复制常规成员<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> pBuffer=new char[nSize]; //复制指针指向的内?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));<br />} </p><p><wbr></p> <p> <wbr> <wbr> <wbr> q样Q定义新对象Qƈ用已有对象初始化新对象时QCExample(const CExample& RightSides)被调用Q而已有对象用别名RightSides传给构造函敎ͼ以用来作复制?/p> <p>  <wbr> <wbr> 原则上,应该为所有包含动态分配成员的c都提供拯构造函数?/p> <p> <wbr> <wbr> <wbr> 拯构造函数的另一U调用:当对象直接作为参Cl函数时Q函数将建立对象的时拷贝,q个拯q程也将调用拯构造函数?/p> <p>例如</p> <p>BOOL testfunc(CExample obj);</p> <p>testfunc(theObjone); //对象直接作ؓ参数?/p> <p>BOOL testfunc(CExample obj)<br />{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> //针对obj的操作实际上是针对复制后的时拷贝进行的<br />} </p><p><wbr></p> <p>q有一U情况,也是与时对象有关的Q当函数中的局部对象被被返回给函数调者时Q也徏立此局部对象的一个时拷贝,拯构造函C被调用</p> <p>CTest func()</p><p>{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CTest theTest;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> return theTest;<br />} </p><p><wbr></p> <p>二、赋值符的重?/p> <p>下面的代码与上例怼</p> <p>int main(int argc, char* argv[])<br />{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample theObjone;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> theObjone.Init(40);<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample theObjthree;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> theObjthree.Init(60);</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> //现在需要一个对象赋值操?被赋值对象的原内容被清除Qƈ用右边对象的内容填充?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> theObjthree=theObjone;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> return 0;<br />}</p><p> <wbr> <wbr> <wbr> 也用C"="P但与之前的例子ƈ不同Q?strong style="color: #ffff00;">之前的例子中Q?="在对象声明语句中Q表C初始化。更多时?q种初始化也可用括号表示?/strong>例如 CExample theObjone(theObjtwo); <strong style="color: #ffff00;">而本例子中,"="表示赋值操作?/strong>对象theObjone的内容复制到对象theObjthree;Q这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。但"="的缺省操作只是将成员变量的值相应复制。旧的D自然丢弃。由于对象内包含指针Q将造成不良后果:指针的D丢弃了,但指针指向的内容q未释放。指针的D复制了,但指针所指内容ƈ未复制?/p> <p> <wbr> <wbr> <wbr> 因此Q包含动态分配成员的c除提供拯构造函数外Q还应该考虑重蝲"="赋值操作符受?/p> <p>cd义变?</p> <p>class CExample<br />{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ...<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample(const CExample&); //拯构造函?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CExample& operator = (const CExample&); //赋值符重蝲<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ...<br />};</p><p>//赋值操作符重蝲<br />CExample & CExample::operator = (const CExample& RightSides)<br />{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> nSize=RightSides.nSize; //复制常规成员<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> char *temp=new char[nSize]; //复制指针指向的内?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> delete []pBuffer; //删除原指针指向内?nbsp;<wbr> (删除操作放在后面,避免X=XҎ(gu)情况下,内容的丢?<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> pBuffer=temp; <wbr> <wbr> //建立新指?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> return *this<br />} </p><p><wbr></p> <p>三、拷贝构造函C用赋D符重蝲的代码?/p> <p>CExample::CExample(const CExample& RightSides)<br />{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> pBuffer=NULL;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> *this=RightSides <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> //调用重蝲后的"="<br />}</p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65382.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:26 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65382.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struct和class区别QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65381.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:25:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65381.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65381.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65381.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65381.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65381.html</trackback:ping><description><![CDATA[<p>1、默认承权限。如果不明确指定Q来自class的承按照privatel承处理Q来自struct的承按照publicl承处理Q?br />2、成员的默认讉K权限。class的成员默认是private权限Qstruct默认是public权限?br /><br />ps:<br />struct和class对于初始化都是需要在初始化列表中q行Q或者在构造函C赋倹{?br /><br /></p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65381.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:25 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65381.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>容器内指针的new和deleteQC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65380.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:23:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65380.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65380.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65380.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65380.html</trackback:ping><description><![CDATA[<p> <wbr> 容器在STL中被认ؓ是智能的。它们支持向前和向后的P代器Q它们能告诉你它所保存的对象类型(通过typedef value_typeQ;在插入和删除q程中它们进行了良好的内存管理;它们报告自己包含了多少对象和自己最多能包含多少对象Q分别通过size和max_size取得Q;q且Q当容器销毁时Q它自动销毁每个被包含的对象?/p> <p> <wbr> 拥有如此聪明的容器,许多E序员自׃再担心清理问题。他们认为容器会Z们操心。多数情况下Q他们正,但是当容器包括由new生对象指针Ӟ他们׃是太正确。毫无疑问,指针容器在销毁时Q会销毁它所包容的每一个元素,但是指针?#8220;析构函数”只是一个空操作。它不会调用delete?/p> <p> <wbr> l果是,以下代码直接D内存资源泄漏Q?/p> <p align=left>void doSomething()</p> <p align=left>{</p> <p align=left>vector<Widget*> vwp;</p> <p align=left>for (int i = 0; i < SOME_MAGIC_NUMBER; ++i)</p> <p align=left>vwp.push_back(new Widget);</p> <p align=left>… // use vwp</p> <p align=left>} //Widgets are leaked here!</p> <p> <wbr> 当离开vwp的作用范围时Qvwp的每一个元素都会被销毁,但是qƈ不改变new所产生的对象没有被deleteq个事实。这个删除动作是E序员的责QQ而不是vector的。这其实是一个功能,因ؓ只有E序员才知道指针是否需要删除?/p> <p> <wbr> 通常Q程序员希望它们那样Q删除指针)。在那种情况Q上例)中,使它发生其实很简单?/p> <p align=left>void doSomething()</p> <p align=left>{</p> <p align=left>vector<Widget*> vwp;</p> <p align=left>… // as before</p> <p align=left>for (vector<Widget*>::iterator i = vwp.begin();i != vwp.end(),++i) {</p> <p align=left>delete *i;</p> <p align=left>}</p> <p>?/p> <p> <wbr> q能行,如果你不是十分在意它只是“能行”。问题之一是新的for循环做了很多for_each做的事,但它不像for_each一h析。另一个问题是代码不是异常安全。如果一个异常在vwp填上指针之后Q而这些指针还没有删除之前被抛出。资源泄漏再ơ出现。幸q的是两个问题都可以克服?/p> <p> <wbr> 修改for_eachcM的代码以使用真正的for_eachQ需要将delete操作|于Q仿Q函数对象中。这像一个儿童游戏,假设你有一个喜Ƣ与STL一L游戏的小孩?/p> <p align=left>template<typename T></p> <p align=left>struct DeleteObject:  <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>// Item 40 describes why</p> <p align=left>public unary_function<const T*, void> { //this inheritance is here</p> <p align=left> <wbr></p> <p align=left>void operator()(const T* ptr) const</p> <p align=left>delete ptr;</p> <p align=left>}</p> <p align=left>};</p> <p> <wbr> 现在你可以这样做Q?/p> <p align=left>void doSomething()</p> <p align=left>{</p> <p align=left>… // as before</p> <p align=left>for_each(vwp.begin(), vwp.end(), DeleteObject<Widget>);</p> <p align=left>}</p> <p> <wbr> 不太走运Q它要求指明DeleteObject删除的对象类型(q里是:Widget Q。o厌,vwp是一个vector<Widget*>Q因此DeteleObject删除的当然是Widget指针Q这U冗余不只是令h讨厌Q因为它可能D难以查的bug出现。试想一下,例如Q有人故意决定要从stringl承Q?/p> <p align=left>class SpecialString: public string { ...};</p> <p> <wbr> q是一U危险的产物Q因为string与其它标准STL容器一P没有virtual析构函数。公有承一个没有虚析构函数的对象是C++一个主要的误区Qa major C++ no-noQ?q一步的l节Q在M一个很好的C++书中都有讨论。在Effective C++中,它被攑֜Item 14)。不论如何,有h如此作了。考虑一下以下代码的行ؓQ?/p> <p align=left>void doSomething()</p> <p align=left>{</p> <p align=left>deque<SpecialString*> dssp;</p> <p align=left>…</p> <p align=left>for_each( dssp.begin(), dssp.end(), // undefined behavior! Deletion</p> <p align=left>DeleteObject<string>()); //of a derived object via a base</p> <p align=left>} // class pointer where there is</p> <p align=left>//no virtual destructor</p> <p> <wbr> 注意dssp声明Z存SpecialString的指针,但是for_each循环的作者告诉DeleteObjectQ它准备删除string的指针。很Ҏ(gu)发现什么样的错误会发生。SpecialString无疑在很大程度上表现为string。因此有Z忘记它的用户Q他们会不记得他们用的是SpecialString而不是string?/p> <p> <wbr> 可以排除q个错误Q也可以减少DeleteObject用户敲打键盘的次敎ͼ使用~译器推l出传给DeleteObject::operator()的指针类型。所有工作只是把模板从DeleteObjectcȝ到operator()上?/p> <p align=left>struct DeleteObject { // templatization and base</p> <p align=left>// class removed here</p> <p align=left>template<typename T> <em>II</em> templatization added here</p> <p align=left>void operator()(const T* ptr) const</p> <p align=left>{</p> <p align=left>delete ptr;</p> <p align=left>}</p> <p align=left>}</p> <p> <wbr> ~译器知道传递给DeleteObject::operatorQ)的指针类型,因此它将自动cd指针生成一个operator的实例。这U类型推l的产生Q取决于我们攑ּDeleteObject的可适应性。考虑一下DeleteObject被设计ؓ如何使用Q就很难扑և可能发生问题的地斏V?/p> <p> <wbr> 使用q一新版的DeleteObjectQSpecialString客户的代码看h像这P</p> <p align=left>void doSomething()</p> <p align=left>{</p> <p align=left>deque<SpecialString*> dssp;</p> <p align=left>…</p> <p align=left>for_each( dssp.begin(), dssp.end(),</p> <p align=left>DeleteObject ()); // ah! well-defined behavior!</p> <p align=left>}</p> <p> <wbr> 直接而且cd安全Q就像我们所喜欢的那栗?/p> <p> <wbr> 但是它还不是异常安全。如果SpecialString生了,但还没有调用for_eachQ一个异常被抛出Q泄漏将出现。这个问题可以用很多Ҏ(gu)解决Q但最单的也许是用智能指针容器取代指针容器,通常使用一个引用记数的指针Q如果不熟?zhn)指针的概念,可以在中高C++ȝ中找到。在More Effective C++中,q些材料在Item 28。)</p> <p> <wbr> STL本nq不包括引用记数的智能指针,~写一个好的-所有情况下都正-太富有技巧,因此除非真的需要,q不需要这样做。我Q作者)1996q在More Effective C++发布了了一个引用记数的指针Q尽它Z一些确定的指针实现Q而且在发布前由多位有l验的开发者讨Q但是这些年q是有一堆准的Bug被发现。很多引用记数的指针可能p|的微妙情况被说明。(l节在More Effective C++勘误中讨论)</p> <p> <wbr> q运圎ͼ几乎不需要自己写一个智能指针,因ؓ已验正的实现q不难找。在Boost库(参考条?0Q中有一个这Lshare_ptr。用Boost的share_ptrQ本条款最初的例子可以重写为:</p> <p align=left>void doSomething()</p> <p align=left>{</p> <p align=left>typedef boost::shared_ ptr<Widget> SPW; //SPW = "shared_ptr</p> <p align=left>// to Widget"</p> <p align=left>vector<SPW> vwp;</p> <p align=left>for (int i = 0; i < SOME_MAGIC_NUMBER; ++i)</p> <p align=left>vwp.push_back(SPW new Widget);  <wbr> <wbr>// create a SPW from a</p> <p align=left>// Widget*, then do a</p> <p align=left>//push_back on it</p> <p align=left>…  <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>// use vwp</p> <p align=left>}  <wbr> <wbr>// no Widgets are leaked here, not</p> <p align=left>// even if an exception is thrown</p> <p align=left>//in the code above</p> <p> <wbr> 千万不能被auto_ptr愚弄了,不要认ؓ创徏auto_ptr的容器,指针会被自动删除。这是可怕是xQ它是如此危险,我准备用整个条款8来说明你不应使用它?/p> <p> <wbr> 应记住的是STL容器是智能的Q但它不以知道是否要删除它包含的指针。ؓ了避免资源泄漏,使用指针容器时应删除指针。你需要用智能指针或在容器销毁前手工删除每一个指针?/p> <p> <wbr> 最后,一个类gDeleteObject的结构可以方便地避免使用指针容器时的资源泄漏Q这也许会你联惌vQ也许可能创Z个类似的DeleteArrayQ避免用数l指针容器时的资源泄漏。当Ӟq是可能的,但是是否明智是另一个问题了。条?3解释了ؓ什么动态申hlL不如vector和string对象。所以在你坐下来写DeleteArray之前Q请先看一看条?3。如果幸q,DeleteArray的时代将永远不会到来?/p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:23 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CStringQMFCQ(C++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65379.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:21:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65379.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65379.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65379.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65379.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65379.html</trackback:ping><description><![CDATA[<font size=5>一、主要函?nbsp;<wbr></font> <p><font style="FONT-SIZE: 14px" size=3>vc中最主要函数不易理解?/font></p> <p><a name=主要函数的实?</a><font style="FONT-SIZE: 14px" size=3>CString::CString(char *p)</font></p> <p><font style="FONT-SIZE: 14px" size=3>{</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> int n=strlen(p);</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>m_data = new char[n+1];</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>strcpy(m_data,p);</font></p> <p><font style="FONT-SIZE: 14px" size=3>}</font></p> <p><font style="FONT-SIZE: 14px" size=3>CString::CString(CString &other)</font></p> <p><font style="FONT-SIZE: 14px" size=3>{</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>int n=strlen(other.m_data);</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>m_data = new char[n+1];</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>strcpy(m_data,other.m_data);</font></p> <p><font style="FONT-SIZE: 14px" size=3>}</font></p> <p><font style="FONT-SIZE: 14px" size=3>CString& CString::operator = (CString& other)</font></p> <p><font style="FONT-SIZE: 14px" size=3>{</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>delete[] m_data;</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>int n=strlen(other.m_data);</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>m_data = new char[n+1];</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>strcpy(m_data,other.m_data);</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>return *this;</font></p> <p><font style="FONT-SIZE: 14px" size=3>}</font></p> <p><font style="FONT-SIZE: 14px" size=3>String::~String()</font></p> <p><font style="FONT-SIZE: 14px" size=3>{</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr>delete [] m_data;</font></p> <p><font style="FONT-SIZE: 14px" size=3>}</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr></font></p> <p><a name=常用函数></a><font style="FONT-SIZE: 14px" size=3>1、CollateQCompare <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></font></p> <p><font style="FONT-SIZE: 14px" size=3>与一个字W长指针所指的字符串进行比较,与strcmp相同Q它们的区别是,分别调用_tcscollQ_tcsicmp?/font></p> <p> <wbr></p> <p><font style="FONT-SIZE: 14px" size=3>2、Delete</font></p> <p><font style="FONT-SIZE: 14px"><strong>int Delete( int</strong> <em>nIndex</em><strong>, int</strong> <em>nCount</em> <strong>= 1 )</strong></font></p> <p><font style="FONT-SIZE: 14px">q回值是被删除前的字W串的长度,nIndex是第一个被删除的字W,nCount是一ơ删除几个字W。根据我实验得出的结果:当nCount>字符串的长度时会出错Q当nCountq大Q没有够的字符删除Ӟ此函C执行?/font></p> <p> <wbr></p> <p><font style="FONT-SIZE: 14px" size=3>3、FindOneOf</font></p> <p><font style="FONT-SIZE: 14px"><strong>int</strong> <strong>FindOneOf(</strong> <strong>LPCTSTR</strong> <em>lpszCharSet</em> <strong>)</strong> <strong>const;</strong></font></p> <p><font style="FONT-SIZE: 14px">此函数的功能是在查找lpszCharSet中的L一个字W,查到一个就把位|返回,没有查到q回0。如Q?/font></p> <p><font style="FONT-SIZE: 14px" size=3>CString str = "0123456789";</font></p> <p><font style="FONT-SIZE: 14px" size=3>int x = str.FindOneOf("31");</font></p> <p><font style="FONT-SIZE: 14px" size=3>x的值是1?/font></p> <p> <wbr></p> <p><font style="FONT-SIZE: 14px" size=3>4、Find</font></p> <p><font style="FONT-SIZE: 14px"><strong>int</strong> <strong>Find(</strong> <strong>TCHAR</strong> <em>ch</em> <strong>)</strong> <strong>const;</strong></font></p> <p><font style="FONT-SIZE: 14px"><strong>int</strong> <strong>Find(</strong> <strong>LPCTSTR</strong> <em>lpszSub</em> <strong>)</strong> <strong>const;</strong></font></p> <p><font style="FONT-SIZE: 14px"><strong>int Find( TCHAR</strong> <em>ch</em><strong>, int</strong> <em>nStart</em> <strong>) const;</strong></font></p> <p><font style="FONT-SIZE: 14px"><strong>int Find( LPCTSTR</strong> <em>pstr</em><strong>, int</strong> <em>nStart</em> <strong>) const;</strong></font></p> <p><font style="FONT-SIZE: 14px" size=3>q回值查扑ֈ的序Pch待搜索的字符QlpszSub待搜索的字符子串QnStart 从那里开始搜索。如Q?/font></p> <p><font style="FONT-SIZE: 14px" size=3>CString str = "0123456789";</font></p> <p><font style="FONT-SIZE: 14px" size=3>int x = str.Find("34",4);</font></p> <p><font style="FONT-SIZE: 14px" size=3>q回的值是-1.</font></p> <p> <wbr></p> <p><font style="FONT-SIZE: 14px" size=3>5、GetAt</font></p> <p><font style="FONT-SIZE: 14px"><strong>TCHAR</strong> <strong>GetAt(</strong> <strong>int</strong> <em>nIndex</em> <strong>)</strong> <strong>const;</strong></font></p> <p><font style="FONT-SIZE: 14px">q回标号为nIndex的字W,你可以把字符串理解ؓ一个数l,GetAtcM于[].注意nIndex的范_如果不合适会有调试错误?/font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr></font></p> <p><font style="FONT-SIZE: 14px" size=3>6、Insert</font></p> <p><font style="FONT-SIZE: 14px"><strong>int Insert( int</strong> <em>nIndex</em><strong>, TCHAR</strong> <em>ch</em> <strong>)</strong><br><strong>int Insert( int</strong> <em>nIndex</em><strong>, LPCTSTR</strong> <em>pstr</em></font> <font style="FONT-SIZE: 14px"><strong>)<br></strong><strong>q回修改后的长度Q?/strong><strong>nIndex</strong><strong>字符Q或字符Ԍ插入后的标号?/strong></font></p> <p> <wbr></p> <p><font style="FONT-SIZE: 14px" size=3>7、Left</font></p> <p><font style="FONT-SIZE: 14px"><strong>CString</strong> <strong>Left(</strong> <strong>int</strong> <em>nCount</em> <strong>)</strong> <strong>const;</strong></font></p> <p><font style="FONT-SIZE: 14px"><strong>q回的字W串的前</strong><strong>nCount</strong><strong>个字W?/strong></font></p> <p><font style="FONT-SIZE: 14px" size=3>Right与LeftcM</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr></font></p> <p><font style="FONT-SIZE: 14px" size=3>8、MakeLower QMakeUpper</font><font style="FONT-SIZE: 14px" size=3>改变字符的大写</font></p> <p><font style="FONT-SIZE: 14px" size=3>MakeReverse字符倒置Q如Q?/font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CString str = "X0123456789";</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> str.MakeReverse();</font></p> <p><font style="FONT-SIZE: 14px" size=3>str变ؓ"9876543210X"</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr></font></p> <p><font style="FONT-SIZE: 14px" size=3>9?=</font></p> <p><font style="FONT-SIZE: 14px"><strong>const</strong> <strong>CString&</strong> <strong>operator</strong> <strong>+=(</strong> <strong>const</strong> <strong>CString&</strong> <em>string</em> <strong>);</strong><br><strong>const</strong> <strong>CString&</strong> <strong>operator</strong> <strong>+=(</strong> <strong>TCHAR</strong> <em>ch</em> <strong>);</strong><br><strong>const</strong> <strong>CString&</strong> <strong>operator</strong> <strong>+=(</strong> <strong>LPCTSTR</strong> <em>lpsz</em> <strong>);</strong></font></p> <p><font style="FONT-SIZE: 14px" size=3>参数合q到自己w上?/font></p> <p><font style="FONT-SIZE: 14px" size=3>如: <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> CString str = "0123456789";</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>  <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> str+="ha";</font></p> <p><font style="FONT-SIZE: 14px" size=3>str?0123456789ha"Q?/font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr></font></p> <p><font style="FONT-SIZE: 14px" size=3>10、str[]</font></p> <p><font style="FONT-SIZE: 14px"><strong>TCHAR</strong> <strong>operator</strong> <strong>[](</strong> <strong>int</strong> <em>nIndex</em> <strong>)</strong> <strong>const;</strong></font></p> <p><font style="FONT-SIZE: 14px" size=3>象处理字W数l一样处理字W串?/font></p> <p><font style="FONT-SIZE: 14px" size=3>注意是只ȝ?/font></p> <p><font style="FONT-SIZE: 14px" size=3>CString str = "0123456789";</font></p> <p><font style="FONT-SIZE: 14px" size=3> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> str[0]='x';</font></p> <p><font style="FONT-SIZE: 14px" size=3>是错误的?/font></p> <p><font style="FONT-SIZE: 14px"> <wbr></font></p> <p align=left><font style="FONT-SIZE: 14px">11、TrimLeft,TrimRight</font></p> <p><font style="FONT-SIZE: 14px">void TrimLeft( );</font></p> <p><font style="FONT-SIZE: 14px">void CString::TrimLeft( TCHAR chTarget );</font></p> <p><font style="FONT-SIZE: 14px">void CString::TrimLeft( LPCTSTR lpszTargets );</font></p> <p><font style="FONT-SIZE: 14px">void TrimRight( );</font></p> <p><font style="FONT-SIZE: 14px">void CString::TrimRight( TCHAR chTarget );</font></p> <p><font style="FONT-SIZE: 14px">void CString::TrimRight( LPCTSTR lpszTargets );</font></p> <p align=left><font style="FONT-SIZE: 14px"> <wbr></font></p> <p align=left><font style="FONT-SIZE: 14px">CString str = "\n\t a";</font></p> <p align=left><font style="FONT-SIZE: 14px">str.TrimLeft();</font></p> <p align=left><font style="FONT-SIZE: 14px">str?#8220;a”;</font></p> <p><font style="FONT-SIZE: 14px"> <wbr> <wbr> <wbr> <wbr>如果没有参数,从左删除字符(\n\tI格{?,臛_遇到一个非此类字符.</font></p> <p><font style="FONT-SIZE: 14px">当然你也可以指定删除那些字符.</font></p> <p><font style="FONT-SIZE: 14px">如果指定的参数是字符?那么遇上其中的一个字W就删除.</font></p> <p align=left><font style="FONT-SIZE: 14px">CString str = "abbcadbabcadb ";</font></p> <p><font style="FONT-SIZE: 14px">str.TrimLeft("ab");</font></p> <p><font style="FONT-SIZE: 14px">l果"cadbabcadb "</font></p> <p><font style="FONT-SIZE: 14px"> <wbr></font></p> <p align=left><font style="FONT-SIZE: 14px">12、int CString::Remove( TCHAR ch );</font></p> <p align=left><font style="FONT-SIZE: 14px">ch删除的字W?</font></p> <p align=left><font style="FONT-SIZE: 14px">q回删除字符的个?有多个时都会删除.</font></p> <p><font style="FONT-SIZE: 14px" size=2> <wbr></font></p> <p><a name=与字W数l之间的怺转换></a><font style="FONT-SIZE: 22px" size=3> <wbr> 二、CString 与char []之间的{? <wbr> <wbr></font></p> <p><font style="FONT-SIZE: 14px" size=3>char str[100] = ”str”;</font></p> <p><font style="FONT-SIZE: 14px" size=3>CString sstr = “sstr”;</font></p> <p><font style="FONT-SIZE: 14px" size=3>str.Format(“%s”,str);</font></p> <p><font style="FONT-SIZE: 14px" size=3>str = LPCTSTR sstr;</font></p> <p><font style="FONT-SIZE: 14px" size=3>strcpy(str,(LPCTSTR)sstr);</font></p> <p><font style="FONT-SIZE: 14px">如果是赋?则要:</font></p> <p><font style="FONT-SIZE: 14px">CString s(_T("This is a test "));<br>LPTSTR p = s.GetBuffer();<br>// 在这里添加用p的代?br>if(p != NULL) *p = _T('\0');<br>s.ReleaseBuffer();<br>// 使用完后及时释放Q以便能使用其它的CString成员函数<br></font></p> <p><font style="FONT-SIZE: 14px">str的值变?</font></p> <p><font style="FONT-SIZE: 14px"> <wbr></font></p> <p><font style="FONT-SIZE: 14px"><font style="FONT-SIZE: 22px"> <wbr> 三、将NULL字节攑օCString?br></font>1,CString str("abc\0""def", 7);<br> <wbr> str +="g";<br> <wbr> int nLength = str.GetLength();<br> <wbr> nLength?.<br>2,CString str("My name is hedan!");<br> <wbr> str.SetAt(5, 0);<br> <wbr> int nLength = str.GetLength();<br>注意:不是所有的CString成员函数都可以,在用时一定要心?/font></p> <p><font style="FONT-SIZE: 14px">实例:动态配|数据源<br>CString strDsn,strDBQ;<br>strDsn = "DSN=test";<br>strDBQ.Format("DBQ=%s",strSourceMDBName);<br>CString strConnect = strDsn + " " + strDBQ ;<br>strConnect.SetAt(strDsn.GetLength(),'\0'); <wbr><br>SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, "Microsoft Access Driver (*.mdb)", strConnect);</font></p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65379.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:21 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65379.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Debug和Release BuildQC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65378.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:20:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65378.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65378.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65378.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65378.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65378.html</trackback:ping><description><![CDATA[Debug版本包括调试信息Q所以要比Release版本大很多(可能大数百KxMQ? <p> <wbr> <wbr> <wbr> 至于是否需要DLL支持Q主要看你采用的~译选项。如果是Z ATL的,则Debug和Release版本对DLL的要求差不多。如果采用的~译选项Z用MFC动态库Q则需要MFC42D.DLL{库支持Q而Release版本需要MFC42.DLL支持?/p> <p> <wbr> <wbr> <wbr> Release Build不对源代码进行调试,不考虑MFC的诊断宏Q用的是MFC Release库,~译时对应用E序的速度q行优化Q而Debug Build则正好相反,它允许对源代码进行调试,可以定义和用MFC的诊断宏Q采用MFC Debug库,寚w度没有优化?nbsp;<wbr> <wbr> <wbr> <wbr><br><br>一、Debug ?Release ~译方式的本质区? <wbr><br> <wbr><br> <wbr> <wbr> <wbr> Debug通常UCؓ调试版本Q它包含调试信息Qƈ且不作Q何优化,便于E序员调试程序。Release UCؓ发布版本Q它往往是进行了各种优化Q得程序在代码大小和运行速度上都是最优的Q以便用户很好地使用? <wbr><br> <wbr> <wbr> <wbr> Debug ?nbsp;<wbr>Release 的真正秘密,在于一l编译选项。下面列Z分别针对二者的选项Q当焉此之外还有其他一些,?Fd?FoQ但区别q不重要Q通常他们也不会引? <wbr>Release  <wbr>版错误,在此不讨论) <wbr> <wbr><br> <wbr> <wbr> <wbr> 1、Debug  <wbr>版本Q? <wbr><br>/MDd /MLd <wbr>?/MTdQ?Debug runtime library(调试版本的运行时d数库)  <wbr><br>/OdQ关闭优化开? <wbr><br>/D "_DEBUG"Q相当于 #define _DEBUG,打开~译调试代码开?主要针对assert函数)  <wbr><br>/ZIQ创? <wbr>Edit  <wbr>and  <wbr>continue(~辑l箋)数据库,q样在调试过E中如果修改了源代码不需重新~译  <wbr><br>/GZQ可以帮助捕获内存错? <wbr><br>/GmQ打开最化重链接开养I减少链接旉 <wbr> <wbr><br> <wbr> <wbr> <wbr> 2、Release  <wbr>版本Q? <wbr>  <wbr><br>/MD /ML ?nbsp;<wbr>/MT  <wbr>使用发布版本的运行时d数库  <wbr><br>/O1 <wbr>?/O2Q优化开养I使程序最或最? <wbr><br>/D "NDEBUG"Q关闭条件编译调试代码开?即不~译assert函数)  <wbr><br>/GFQ合q复的字符Ԍq将字符串常量放到只d存,防止被修?nbsp;<wbr> <wbr><br> <wbr> <wbr> <wbr> 实际上,Debug  <wbr>? <wbr>Release  <wbr>q没有本质的界限Q他们只是一l编译选项的集合,~译器只是按照预定的选项行动。事实上Q我们甚臛_以修改这些选项Q从而得C化过的调试版本或是带跟踪语句的发布版本? <wbr><br> <wbr><br>二、哪些情况下  <wbr>Release  <wbr>版会出错  <wbr><br> <wbr><br> <wbr> <wbr> <wbr> 有了上面的介l,我们再来逐个对照q些选项看看  <wbr>Release  <wbr>版错误是怎样产生的?/p> <p> <wbr><br> <wbr> <wbr> <wbr> 1.Runtime LibraryQ?/p> <p>链接哪种q行时刻函数库通常只对E序的性能产生影响。调试版本的Runtime Library 包含了调试信息,q用了一些保护机制以帮助发现错误Q因此性能不如发布版本。编译器提供?Runtime Library 通常很稳定,不会造成 <wbr>Release 版错误;倒是׃ Debug ?Runtime <wbr>Library <wbr>加强了对错误的检,如堆内存分配Q有时会出现 Debug 有错?nbsp;<wbr>Release 正常的现象。应当指出的是,如果 Debug <wbr>有错Q即 <wbr>Release  <wbr>正常Q程序肯定是?nbsp;<wbr>Bug <wbr>的,只不q可能是 Release <wbr>版的某次q行没有表现出来而已?nbsp;<wbr></p> <p> <wbr><br> <wbr> <wbr> <wbr> 2.优化Q?/p> <p>q是造成错误的主要原因,因ؓ关闭优化时源E序基本上是直接译的,而打开优化后编译器会作Zpd假设。这c错误主要有以下几种Q?/p> <p>(1)  <wbr>帧指?Frame Pointer)省略Q简UFPOQ:</p> <p>在函数调用过E中Q所有调用信息(q回地址、参敎ͼ以及自动变量都是攑֜栈中的。若函数的声明与实现不同Q参数、返回倹{调用方式)Q就会生错误。但 Debug 方式下,栈的讉K通过  <wbr>EBP  <wbr>寄存器保存的地址实现Q如果没有发生数l越界之cȝ错误Q或是越?#8220;不多”Q,函数通常能正常执行。Release 方式下,优化会省?EBP 栈基址指针Q这样通过一个全局指针讉K栈就会造成q回地址错误是程序崩溃。C++ 的强cdҎ(gu)能查出大多数这L错误Q但如果用了强制cd转换Q就不行了。你可以?Release 版本中强制加?/Oy- ~译选项来关掉指针省略Q以定是否此类错误?/p> <p>此类错误通常有: <wbr></p> <p>MFC 消息响应函数书写错误?/p> <p>正确的应? <wbr><br>afx_msg  <wbr>LRESULT  <wbr>OnMessageOwn(WPARAM  <wbr>wparam,  <wbr>LPARAM  <wbr>lparam);  <wbr><br>ON_MESSAGE  <wbr>宏包含强制类型{换。防止这U错误的Ҏ(gu)之一是重定义 ON_MESSAGE 宏,把下列代码加?stdafx.h 中(?include "afxwin.h"之后Q?函数原Ş错误时编译会报错  <wbr><br>#undef ON_MESSAGE  <wbr><br>#define ON_MESSAGE(message, <wbr>memberFxn) \  <wbr><br>{ <wbr>message, 0, <wbr>0, <wbr>0, AfxSig_lwl, \  <wbr><br>(AFX_PMSG)(AFX_PMSGW)(static_cast< <wbr>LRESULT (AFX_MSG_CALL \  <wbr><br>CWnd::*)(WPARAM, LPARAM) <wbr>> (&memberFxn) <wbr>}, <wbr> <wbr><br>(2)  <wbr>volatile  <wbr>型变量:</p> <p>volatile 告诉~译器该变量可能被程序之外的未知方式修改Q如pȝ、其他进E和U程Q。优化程序ؓ了ɽE序性能提高Q常把一些变量放在寄存器中(cM?register 关键字)Q而其他进E只能对该变量所在的内存q行修改Q而寄存器中的值没变。如果你的程序是多线E的Q或者你发现某个变量的g预期的不W而你信已正的讄了,则很可能遇到q样的问题。这U错误有时会表现为程序在最快优化出错而最优化正常。把你认为可疑的变量加上 volatile 试试?nbsp;<wbr> <wbr><br>(3)  <wbr>变量优化Q?/p> <p>优化E序会根据变量的使用情况优化变量。例如,函数中有一个未被用的变量Q在 <wbr>Debug <wbr>版中它有可能掩盖一个数l越界,而在 Release 版中Q这个变量很可能被优化,此时数组界会破坏栈中有用的数据。当Ӟ实际的情况会比这复杂得多。与此有关的错误有: <wbr> <wbr><br>非法讉KQ包括数l越界、指针错误等。例? <wbr><br>void  <wbr>fn(void)  <wbr><br>{  <wbr><br> <wbr> <wbr> <wbr> int  <wbr>i;  <wbr><br> <wbr> <wbr> <wbr> i  <wbr>=  <wbr>1;  <wbr><br> <wbr> <wbr> <wbr> int  <wbr>a[4];  <wbr><br> <wbr> <wbr> <wbr> {  <wbr><br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> int  <wbr>j;  <wbr><br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> j  <wbr>=  <wbr>1;  <wbr><br> <wbr> <wbr> <wbr> }  <wbr><br> <wbr> <wbr> <wbr> a[-1]  <wbr>=  <wbr>1;//当然错误不会q么明显Q例如下标是变量  <wbr><br> <wbr> <wbr> <wbr> a[4]  <wbr>=  <wbr>1;  <wbr><br>}  <wbr><br>j 虽然在数l越界时已出了作用域Q但其空间ƈ未收回,因?i <wbr>?j ׃掩盖界。?nbsp;<wbr>Release <wbr>版由?nbsp;<wbr>i、j q未其很大作用可能会被优化掉Q从而栈被破坏?nbsp;<wbr> <wbr></p> <p><br>3. _DEBUG ?NDEBUGQ?/p> <p>当定义了 <wbr>_DEBUG Ӟassert() <wbr>函数会被~译Q?NDEBUG <wbr>时不被编译。除此之外,VC++中还有一pd断言宏。这包括Q?nbsp;<wbr> <wbr><br>ANSI C 断言 void assert(int expression );  <wbr><br>C Runtime Lib 断言 _ASSERT( booleanExpression );  <wbr><br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> _ASSERTE( booleanExpression );  <wbr><br>MFC  <wbr>断言  <wbr>ASSERT(  <wbr>booleanExpression  <wbr>);  <wbr><br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> VERIFY(  <wbr>booleanExpression  <wbr>); <wbr> <wbr><br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ASSERT_VALID(  <wbr>pObject  <wbr>);  <wbr><br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> ASSERT_KINDOF(  <wbr>classname,  <wbr>pobject  <wbr>);  <wbr><br>ATL  <wbr>断言  <wbr>ATLASSERT(  <wbr>booleanExpression  <wbr>);  <wbr><br>此外QTRACE()  <wbr>宏的~译也受  <wbr>_DEBUG  <wbr>控制?nbsp;<wbr> <wbr><br> <wbr> <wbr> <wbr> 所有这些断a都只? <wbr>Debug版中才被~译Q而在  <wbr>Release  <wbr>版中被忽略。唯一的例外是  <wbr>VERIFY() 。事实上Q这些宏都是调用? <wbr>assert()  <wbr>函数Q只不过附加了一些与库有关的调试代码。如果你在这些宏中加入了ME序代码Q而不只是布尔表达式(例如赋倹{能改变变量值的函数调用{)Q那? <wbr>Release  <wbr>版都不会执行q些操作Q从而造成错误。初学者很Ҏ(gu)犯这c错误,查找的方法也很简单,因ؓq些宏都已在上面列出Q只要利? <wbr>VC++  <wbr>? <wbr>Find  <wbr>in  <wbr>Files 功能在工E所有文件中扑ֈ用这些宏的地方再一一查即可。另外,有些高手可能q会加入  <wbr>#ifdef  <wbr>_DEBUG  <wbr>之类的条件编译,也要注意一下? <wbr><br> <wbr> <wbr> <wbr> Z值得一提的? <wbr>VERIFY()  <wbr>宏,q个宏允怽程序代码放在布?yu)表辑ּ里。这个宏通常用来? <wbr>Windows  <wbr>API  <wbr>的返回倹{有些h可能个原因而滥?nbsp;<wbr>VERIFY() Q事实上q是危险的,因ؓ <wbr>VERIFY() q反了断a的思想Q不能ɽE序代码和调试代码完全分,最l可能会带来很多ȝ。因此,专家们徏议尽量少用这个宏?nbsp;<wbr> <wbr></p> <p><br>4.  <wbr>/GZ  <wbr>选项Q?/p> <p>q个选项会做以下q些?nbsp;<wbr>Q?nbsp;<wbr><br>(1)  <wbr>初始化内存和变量?/p> <p>包括? <wbr>0xCC  <wbr>初始化所有自动变量,0xCD  <wbr>(  <wbr>Cleared  <wbr>Data  <wbr>)  <wbr>初始化堆中分配的内存Q即动态分配的内存Q例? <wbr>new  <wbr>Q,0xDD  <wbr>(  <wbr>Dead  <wbr>Data  <wbr>)  <wbr>填充已被释放的堆内存Q例? <wbr>delete  <wbr>Q,0xFD(  <wbr>deFencde  <wbr>Data  <wbr>)  <wbr>初始化受保护的内存(debug  <wbr>版在动态分配内存的前后加入保护内存以防止越界访问)Q其中括号中的词是微软徏议的助记词。这样做的好处是q些值都很大Q作为指针是不可能的Q而且  <wbr>32  <wbr>位系l中指针很少是奇数|在有些系l中奇数的指针会产生q行旉误)Q作为数g很少遇到Q而且q些g很容易L认,因此q很有利于在  <wbr>Debug  <wbr>版中发现  <wbr>Release  <wbr>版才会遇到的错误。要特别注意的是Q很多h认ؓ~译器会? <wbr>0  <wbr>来初始化变量Q这是错误的Q而且q样很不利于查找错误Q? <wbr><br>(2)  <wbr>通过函数指针调用函数Ӟ会通过查栈指针验证函数调用的匹配性。(防止原Ş不匹配)  <wbr><br>(3)  <wbr>函数q回前检查栈指针Q确认未被修攏V(防止界讉K和原形不匚wQ与W二合在一起可大致模拟帧指针省? <wbr>FPO  <wbr>Q?nbsp;<wbr> <wbr><br> <wbr> <wbr> <wbr> 通常  <wbr>/GZ  <wbr>选项会造成  <wbr>Debug  <wbr>版出错? <wbr>Release  <wbr>版正常的现象Q因? <wbr>Release  <wbr>版中未初始化的变量是随机的,q有可能使指针指向一个有效地址而掩盖了非法讉K?nbsp;<wbr> <wbr><br><br> <wbr> <wbr> <wbr> 除此之外Q?Gm  <wbr>/GF  <wbr>{选项造成错误的情冉|较少Q而且他们的效果显而易见,比较Ҏ(gu)发现?nbsp;<wbr> <wbr><br></p> <p>短地_<br> <wbr> <wbr> <wbr> Release是发行版?比Debug版本有一些优化,文g比Debug文g。Debug是调试版本,包括的程序信息更多。ReleaseҎ(gu)Q?build->batchQbuild->buildO(jin)K. <wbr>只有DEBUG版的E序才能讄断点、单步执行、用TRACE/ASSERT{调试输句。REALEASE不包含Q何调试信息,所以体U小、运行速度快?/p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65378.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:20 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65378.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数指针QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65377.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:20:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65377.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65377.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65377.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65377.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65377.html</trackback:ping><description><![CDATA[<p>1、函数指针同h可以作ؓ参数传递给函数的?/p> <p class="code">#include <wbr><iostream> <wbr> <wbr> <wbr><br />#include <wbr><string> <wbr> <wbr> <wbr><br />using <wbr>namespace <wbr>std; <wbr> <wbr> <wbr> <wbr> <wbr><br />int <wbr>test(int); <wbr> <wbr> <wbr> <wbr><br />int <wbr>test2(int <wbr>(*ra)(int),int); <wbr><br />void <wbr>main(int <wbr>argc,char* <wbr>argv[]) <wbr> <wbr> <wbr> <wbr> <wbr><br />{ <wbr> <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr>cout<<test<<endl; <wbr><br /> <wbr> <wbr> <wbr> <wbr>typedef <wbr>int <wbr>(*fp)(int); <wbr> <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr>fp <wbr>fpi; <wbr><br /> <wbr> <wbr> <wbr> <wbr>fpi=test; <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr>cout<<test2(fpi,1)<<endl;<br /> <wbr> <wbr> <wbr> <wbr>cin.get(); <wbr><br />} <wbr> <wbr> <wbr> <wbr><br />int <wbr>test(int <wbr>a) <wbr><br />{ <wbr> <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr>return <wbr>a-1; <wbr><br />} <wbr><br />int <wbr>test2(int <wbr>(*ra)(int),int <wbr>b)//q里定义了一个名字ؓra的函数指?nbsp;<wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>int <wbr>c=ra(10)+b;//在调用之?ra已经指向fpi所指向的函数地址即test函数 <wbr><br /> <wbr> <wbr> <wbr> <wbr>return <wbr>c; <wbr><br />}</p> <p>2、利用函数指针,我们可以构成指针数组Q更明确点的说法是构成指向函数的指针数组Q这么说可能容易理解的多了?/p> <p class="code">#include <wbr><iostream> <wbr> <wbr> <wbr><br />#include <wbr><string> <wbr> <wbr> <wbr><br />using <wbr>namespace <wbr>std; <wbr><br />void <wbr>t1(){cout<<"test1";} <wbr><br />void <wbr>t2(){cout<<"test2";} <wbr><br />void <wbr>t3(){cout<<"test3";} <wbr><br />void <wbr>main(int <wbr>argc,char* <wbr>argv[]) <wbr> <wbr> <wbr> <wbr> <wbr><br />{ <wbr><br /> <wbr> <wbr> <wbr> <wbr>void* <wbr>a[]={t1,t2,t3}; <wbr><br /> <wbr> <wbr> <wbr> <wbr>cout<<"比较t1()的内存地址和数la[0]所存储的地址是否一?<<t1<<"|"<<a[0]<<endl; <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr>cout<<a[0]();//错误!指针数组是不能利用数l下标操作调用函数的 <wbr> <wbr><br /> <wbr> <wbr> <wbr> <wbr>typedef <wbr>void <wbr>(*fp)();//自定义一个函数指针类?nbsp;<wbr><br /> <wbr> <wbr> <wbr> <wbr>fp <wbr>b[]={t1,t2,t3}; <wbr>//利用自定义类型fp把b[]定义成一个指向函数的指针数组 <wbr><br /> <wbr> <wbr> <wbr> <wbr>b[0]();//现在利用指向函数的指针数l进行下标操作就可以q行函数的间接调用了; <wbr><br /> <wbr> <wbr> <wbr> <wbr>cin.get(); <wbr><br />}</p> <p class="code">另外Q?/p> <p class="code">void* a[]={t1,t2,t3};<br />cout<<"比较t1()的内存地址和数la[0]所存储的地址是否一?<<t1<<"|"<<a[0]<<endl;<br />cout<<a[0]();</p> <p>上面的这一段中的错误行,Z么不能这么调用呢Q指针数l元素所保存的只是一个内存地址Q既然只是个内存地址׃可能q行a[0]()q样地址带括L操作Q而函数指针不同,它是一个例外,函数指针只所以这么叫它就是因为它是指向函数指向内存的代码区的指针Q它被系l授予允怸()括号操作的权利,q行<strong>间接的函数调?/strong>Q既然函数指针允许这么操作,那么被定义成函数指针的数l就一定是可以一L操作的?/p> <p> <wbr></p> <p>3、类的成员函敎ͼ</p> <p><span><span>class CA<br />{<br /> <wbr>public:<br /> <wbr> <wbr> <wbr> char lcFun(int a){ return; }<br />};<br />CA ca;<br />typedef char (CA::*PTRFUN)(int);<br />PTRFUN pFun;<br />void main()<br />{<br /> <wbr> <wbr> <wbr> pFun = CA::lcFun;<br /> <wbr> <wbr> <wbr> ca.(*pFun)(2);<br />}</span> <span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US"><br /><span style="font-size: 10.5pt; font-family: 宋体">在这里,指针的定义与使用都加上了</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">“</span><span style="font-size: 10.5pt; font-family: 宋体">c限?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">”</span><span style="font-size: 10.5pt; font-family: 宋体">?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">“</span><span style="font-size: 10.5pt; font-family: 宋体">对象</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">”</span><span style="font-size: 10.5pt; font-family: 宋体">Q用来指明指针指向的函数是那个类的这里的cd象也可以是?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">new</span><span style="font-size: 10.5pt; font-family: 宋体">得到的。比如:</span> <span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US"><br />CA *pca = new CA;<br />pca->(*pFun)(2);<br />delete pca;<br /></span><span style="font-size: 10.5pt; font-family: 宋体">而且q个cd象指针可以是cd部成员变量,你甚臛_以?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">this</span><span style="font-size: 10.5pt; font-family: 宋体">指针。比如:</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US"><br /></span><span style="font-size: 10.5pt; font-family: 宋体">c?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">CA</span><span style="font-size: 10.5pt; font-family: 宋体">有成员变?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">PTRFUN m_pfun;<br />void CA::lcFun2()<br />{ <wbr><br /> <wbr> <wbr> (this->*m_pFun)(2);<br />}<br /></span><span style="font-size: 10.5pt; font-family: 宋体">一句话Q用类成员函数指针必须?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">“->*”</span><span style="font-size: 10.5pt; font-family: 宋体">?/span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'" xml:lang="EN-US">“.*”</span><span style="font-size: 10.5pt; font-family: 宋体">的调用?/span></span></span></p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65377.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:20 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65377.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>typedefQC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65376.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:19:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65376.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65376.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65376.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65376.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65376.html</trackback:ping><description><![CDATA[<p>一、基本用法:</p> <p align=left>1、普通类?/p> <p align=left>typedef unsigned int UINT;</p> <p align=left>2、struct</p> <p align=left>typedef struct {int x; int y;} Point;</p> <p align=left>或?/p> <p align=left>typedef struct t_node {</p> <p align=left> <wbr> <wbr> <wbr> int Value;</p> <p align=left> <wbr> <wbr> <wbr> struct t_node *next;</p> <p align=left>} Node;</p> <p align=left>或?/p> <p align=left>typedef strcut t_node Node;</p> <p align=left>struct t_node {</p> <p align=left> <wbr> <wbr> <wbr> int Value;</p> <p align=left> <wbr> <wbr> <wbr> Node *next;</p> <p align=left>};</p> <p align=left>3、函数指?/p> <p align=left>typedef void (*FUNCADDR)(int);</p> <p align=left>4、类cd</p> <p align=left>typedef class {</p> <p align=left> <wbr> <wbr> <wbr> private:</p> <p align=left> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> int a;</p> <p align=left> <wbr> <wbr> <wbr> public:</p> <p align=left> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> int b;</p> <p align=left>} MyClass;</p> <p align=left> <wbr></p> <p align=left>二、深入讨论:</p> <p align=left><strong><u>1、关于const 和指?/u></strong></p> <p align=left>typedef char * pstr;<br>int mystrcmp(pstr, pstr);<br>  q里带我们到达W一?typedef 陷阱。标准函?strcmp()有两?#8216;const char *'cd的参数。因此,它可能会误导Z象下面这样声?mystrcmp()Q?/p> <p align=left>int mystrcmp(const pstr, const pstr);<br>  q是错误的,按照序Q?#8216;const pstr'被解释ؓ‘char * const'Q一个指?char 的常量指针)Q而不?#8216;const char *'Q指向常?char 的指针)?/p> <p align=left> <wbr> <wbr> <wbr> q个问题很容易解冻I</p> <p align=left>typedef const char * cpstr;<br>int mystrcmp(cpstr, cpstr); // 现在是正的</p> <p align=left>2、文本替?/p> <p align=left> <wbr> <wbr> <wbr> typedef 行ؓ有点?nbsp;<wbr>#define <wbr>宏,用其实际cd替代同义字。不同点?typedef 在编译时被解释,因此让编译器来应付超预处理器能力的文本替换?/p> <p align=left>例如:</p> <p align=left>typedef int <wbr>(*PF) <wbr>(const char <wbr>*, const char <wbr>*);</p> <p align=left>如果要用下列Ş式的函数声明Q那么上q这?typedef 是不可或~的Q?/p> <p align=left>PF Register(PF pf);<br>展示一下如果不?typedefQ我们是如何实现q个声明的:</p> <p align=left>int (*Register (int (*pf)(const char *, const char *)))(const char *, const char *);<br>3、存储类关键?/p> <p align=left> <wbr> <wbr> <wbr> typedef 像 autoQexternQmutableQstaticQ和 register 一P是一个存储类关键字?/p> <p align=left>W二个陷阱:</p> <p align=left>typedef register int FAST_COUNTER; // 错误<br>~译通不q。问题出在你不能在声明中有多个存储类关键字。因为符?typedef 已经占据了存储类关键字的位置Q在 typedef 声明中不能用 registerQ或M其它存储cd键字Q?/p> <p align=left>4、定义机器无关的cd</p> <p align=left> <wbr> <wbr> <wbr> 例如Q你可以定义一个叫 REAL 的Q点类型,在目标机器上它可以i获得最高的_ֺQ?/p> <p align=left>typedef long double REAL;<br>在不支持 long double 的机器上Q该 typedef 看v来会是下面这P</p> <p align=left>typedef double REAL;<br>q且Q在q?double 都不支持的机器上Q该 typedef 看v来会是这P</p> <p align=left>typedef float REAL;<br>  你不用对源代码做M修改Q便可以在每一U^C~译q个使用 REAL cd的应用程序。唯一要改的是 typedef 本n。在大多数情况下Q甚臌个微的变动完全都可以通过奇妙的条件编译来自动实现。不是吗? 标准库广泛地使用 typedef 来创Lq_无关cdQsize_tQptrdiff ?fpos_t 是其中的例子。此外,?std::string ?std::ofstream q样?typedef q隐藏了镉K的,难以理解的模板特化语法,例如Qbasic_string<char, char_traits<char>Qallocator<char>> ?basic_ofstream<char, char_traits<char>>?/p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65376.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:19 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65376.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>构造函C的this指针QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65375.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:19:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65375.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65375.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65375.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65375.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65375.html</trackback:ping><description><![CDATA[<p>-------------------------------原理-------------------------------</p> <p>某些Z应该在构造函C使用this指针Q因时this对象q没有完全Ş成?/p> <p>但是Q只要小心,是可以在构造函C使用this指针的:</p> <p>●在函数体中</p> <p>●初始化列表?/p> <p>因ؓ“对象q没有完全Ş?#8221;不意味着“什么都没有”?/p> <p>在进入构造函敎ͼ及其chainingQ之前,Compiler会:</p> <p>●给class的instance分配内存</p> <p>●徏立运行时ȝl所需的信息(如vtbl{)</p> <p>?#~省?# 构造所有类成员<br><img src="http://www.vckbase.com/document/journal/vckbase26/images/this-pattern.gif" width=441 height=450><br>-----------------------------【能?--------------------------------</p> <p>构造函数的函数体(或构造函数所调用的函敎ͼ【能】可靠地讉KQ?/p> <p>●基cM声明的数据成?/p> <p>●构造函数所属类声明的数据成?/p> <p>q是因ؓ所有这些数据成员被保证在构造函数函C开始执行时已经被完整的建立?/p> <p>-----------------------------【不能?--------------------------------</p> <p>构造函数的函数体(或构造函数所调用的函敎ͼ【不能】向下调用:</p> <p>●被zc重定义的虚函数</p> <p>q是因ؓ在基cȝ构造函数执行期_“对象q不是一个派生类的对?#8221;?/p> <p>---------------------------【有时?----------------------------------</p> <p>以下是【有时】可行的Q?/p> <p>●传?this 对象的Q何一个数据成员给另一个数据成员的初始化程?/p> <p>你必ȝ保该数据成员已经被初始化。好消息是你能用一些不依赖于你所使用的编译器的显著的语言规则Q来定那个数据成员是否已经Q或者还没有Q被初始化。坏消息是你必须知道q些语言规则Q例如,基类子对象首先被初始化(如果有多重和Q或虚承,则查询这个次序!Q,然后cM定义的数据成员根据在cM声明的次序被初始化)。如果你不知道这些规则,则不要从this对象传递Q何数据成员(不论是否昑ּ的用了this关键字)lQ何其他数据成员的初始化程序!如果你知道这些规则,则需要小心?/p> <p>----------------------------用?---------------------------------</p> <p>好的OO设计“高聚?#8221;Q这样会产生很多的责Q单一的对?其实“单一责Q原则”Ҏ(gu)是最基础的OO原则)?/p> <p>那么Q小对象之间的协作就需要配|?其实“协作可配|?#8221;本n是我们希望的灵zL所?Q?/p> <p>●比如Observer模式中subject和observer的协作需要调subject.RegistorObserver(observer)来配|?/p> <p>●再比如多媒体框架DirectShow中filterGraph和videoWindow的协作需要调filterGraph.SetVideoWindow(videoWindow)来配|?/p> <p>而构造函数是很典型的配置时机QD例如下:</p> <p><br>class CMyWindow : public CWnd<br>{<br>private:<br>CFilterGraph filterGraph;<br>public<br>CMyWindow() { filterGraph.SetVideoWindow(this); };<br>};<br>--------------------------附录------------------------------------</p> <p>需要明了的是,【构?析构/普通】和【虚/非虚】是完全独立的分cL式:<br>●只要是“构?析构”?#8220;串联(chaining)”<br>●只要是“虚函?#8221;?#8220;可能obj.vfun()”</p> <p>它们可以“一L?#8221;?#8220;不互相干?#8221;Q比如虚析构函数的情况,看下面的例子Q?/p> <pre>class superclass <br>{ <br>   virtual ~superclass() <br>   { <br>      println("superclass::~superclass()"); <br>   } <br>}; <br>class subclass : public superclass <br>{ <br>   virtual ~subclass() <br>   { <br>      println("subclass::~subclass()"); <br>   } <br>};</pre> 执行 <pre>superclass * super = new subclass(); </pre> <pre>delete super;</pre> 的结果是打印? <pre>subclass::~subclass() </pre> <pre>superclass::~superclass()</pre> q意味着当执行delete super;Ӟ<br>●是否是chaining式call呢?是。因为是析构函数?br>●那chaining call从哪里开始呢Q从subclass::~subclass() ==〉superclass::~superclass()Q?br>因ؓsuperclass * super的实际对象的cd是subclass? <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:19 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>this指针QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65372.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:16:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65372.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65372.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65372.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65372.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65372.html</trackback:ping><description><![CDATA[有下面的一个简单的c: <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> <wbr>CNullPointCall<br>{<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>Test1();<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>Test2();<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>Test3(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> <wbr>iTest);<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>Test4();<br><br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> <wbr>m_iStatic;<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> <wbr>m_iTest;<br>};<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> <wbr>CNullPointCall::m_iStatic <wbr></span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>CNullPointCall::Test1()<br>{<br> <wbr> <wbr> <wbr> <wbr>cout <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>m_iStatic <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>endl;<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>CNullPointCall::Test2()<br>{<br> <wbr> <wbr> <wbr> <wbr>cout <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Very <wbr>Cool!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>endl; <wbr><br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>CNullPointCall::Test3(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> <wbr>iTest)<br>{<br> <wbr> <wbr> <wbr> <wbr>cout <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>iTest <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>endl; <wbr><br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>CNullPointCall::Test4()<br>{<br> <wbr> <wbr> <wbr> <wbr>cout <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>m_iTest <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>endl; <wbr><br>}</span></div> </div> <div> <wbr> <wbr> <wbr> 那么下面的代码都正确吗?都会输出什么?</div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #000000">CNullPointCall <wbr></span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pNull <wbr></span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <wbr>NULL; <wbr></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>没错Q就是给指针赋gؓI?/span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test1();</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>call <wbr>1</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test2(); <wbr></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>call <wbr>2</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test3(</span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">); <wbr></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>call <wbr>3</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test4(); <wbr><span style="COLOR: #008000">/</span></span><span style="COLOR: #008000">/</span><span style="COLOR: #008000"> <wbr>call <wbr>4</span></div> </div> <div> <wbr> <wbr> <wbr> 你肯定会很奇怪我Z么这么问。一个gؓNULL的指针怎么可以用来调用cȝ成员函数呢?Q可是实事却很让人吃惊:除了call 4那行代码以外Q其?个类成员函数的调用都是成功的Q都能正的输出l果Q而且包含q?行代码的E序能非常好的运行?br> <wbr> <wbr> <wbr> l过l心的比较就可以发现Qcall 4那行代码跟其?行代码的本质区别Q类CNullPointCall的成员函C用到了this指针?br> <wbr> <wbr> <wbr> 对于cL员函数而言Qƈ不是一个对象对应一个单独的成员函数体,而是此类的所有对象共用这个成员函C。当E序被编译之后,此成员函数地址卛_定。而成员函C所以能把属于此cȝ各个对象的数据区别开, 是靠这个this指针。函C内所有对cL据成员的讉KQ都会被转化为this->数据成员的方式?br> <wbr> <wbr> <wbr> 而一个对象的this指针q不是对象本w的一部分Q不会媄响sizeofQ?#8220;对象”Q的l果。this作用域是在类内部Q当在类的非静态成员函C讉Kcȝ非静态成员的时候,~译器会自动对象本w的地址作ؓ一个隐含参C递给函数。也是_即你没有写上this指针Q编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参Q对各成员的讉K均通过thisq行?br> <wbr> <wbr> <wbr> 对于上面的例子来_this的g是pNull的倹{也是说this的gؓNULL。而Test1()是静态函敎ͼ~译器不会给它传递this指针Q所以call 1那行代码可以正确调用Q这里相当于CNullPointCall::Test1()Q;对于Test2()和Test3()两个成员函数Q虽然编译器会给q两个函C递this指针Q但是它们ƈ没有通过this指针来访问类的成员变量,因此call 2和call 3两行代码可以正确调用Q而对于成员函数Test4()要访问类的成员变量,因此要用this指针Q这个时候发现this指针的gؓNULLQ就会造成E序的崩溃?nbsp;<wbr> <wbr> <wbr><br> <wbr> <wbr> <wbr> 其实Q我们可以想象编译器把Test4()转换成如下的形式Q?/div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>CNullPointCall::Test4(CNullPointCall <wbr></span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">)<br>{<br> <wbr> <wbr> <wbr> <wbr>cout <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">m_iTest <wbr></span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> <wbr>endl; <wbr><br>}</span></div> </div> <div> <wbr> <wbr> <wbr> 而把call 4那行代码转换成了下面的Ş式:</div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #000000">CNullPointCall::Test4(pNull);</span></div> </div> <div> <wbr> <wbr> <wbr> 所以会在通过this指针讉Km_iTest的时候造成E序的崩溃?br> <wbr> <wbr> <wbr> 下面通过查看上面代码用VC 2005~译后的汇编代码来详l解释一下神奇的this指针?br> <wbr> <wbr> <wbr> 上面的C++代码~译生成的汇~代码是下面的Ş式:</div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #000000"> <wbr> <wbr> <wbr> <wbr>CNullPointCall <wbr></span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pNull <wbr></span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <wbr>NULL;<br>0041171E <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>dword <wbr>ptr <wbr>[pNull],</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> <wbr><br> <wbr> <wbr> <wbr> <wbr>pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test1();<br></span><span style="COLOR: #000000">00411725</span><span style="COLOR: #000000"> <wbr> <wbr>call <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>CNullPointCall::Test1 <wbr>(411069h) <wbr><br> <wbr> <wbr> <wbr> <wbr>pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test2();<br>0041172A <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ecx,dword <wbr>ptr <wbr>[pNull] <wbr><br>0041172D <wbr> <wbr>call <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>CNullPointCall::Test2 <wbr>(4111E0h) <wbr><br> <wbr> <wbr> <wbr> <wbr>pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test3(</span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #000000">00411732</span><span style="COLOR: #000000"> <wbr> <wbr>push <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>0Dh <wbr> <wbr><br></span><span style="COLOR: #000000">00411734</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ecx,dword <wbr>ptr <wbr>[pNull] <wbr><br></span><span style="COLOR: #000000">00411737</span><span style="COLOR: #000000"> <wbr> <wbr>call <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>CNullPointCall::Test3 <wbr>(41105Ah) <wbr><br> <wbr> <wbr> <wbr> <wbr>pNull</span><span style="COLOR: #000000">-></span><span style="COLOR: #000000">Test4();<br>0041173C <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ecx,dword <wbr>ptr <wbr>[pNull] <wbr><br>0041173F <wbr> <wbr>call <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>CNullPointCall::Test4 <wbr>(411032h) <wbr></span></div> </div> <div> <wbr> <wbr> <wbr> 通过比较静态函数Test1()和其?个非静态函数调用所生成的的汇编代码可以看出Q非静态函数调用之前都会把指向对象的指针pNullQ也是this指针Q放到ecx寄存器中Qmov ecx,dword ptr [pNull]Q。这是this指针的特D之处。看call 3那行C++代码的汇~代码就可以看到this指针跟一般的函数参数的区别:一般的函数参数是直接压入栈中(push 0DhQ,而this指针却被攑ֈ了ecx寄存器中。在cȝ非成员函C如果要用到类的成员变量,可以通过讉Kecx寄存器来得到指向对象的this指针Q然后再通过this指针加上成员变量的偏U量来找到相应的成员变量?br> <wbr> <wbr> <wbr> 下面再通过另外一个例子来说明this指针是怎样被传递到成员函数中和如何使用this来访问成员变量的?br> <wbr> <wbr> <wbr> 依然是一个很单的c:</div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> <wbr>CTest<br>{<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>SetValue();<br><br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> <wbr>m_iValue1;<br> <wbr> <wbr> <wbr> <wbr></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> <wbr>m_iValue2;<br>};<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>CTest::SetValue()<br>{<br> <wbr> <wbr> <wbr> <wbr>m_iValue1 <wbr></span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">;<br> <wbr> <wbr> <wbr> <wbr>m_iValue2 <wbr></span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">;<br>}</span></div> </div> <div> <wbr> <wbr> <wbr> 用如下的代码调用成员函数Q?/div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #000000">CTest <wbr>test;<br>test.SetValue();<br></span></div> </div> <div> <wbr> <wbr> <wbr> 上面的C++代码的汇~代码ؓQ?/div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #000000"> <wbr> <wbr> <wbr> <wbr>CTest <wbr>test;<br> <wbr> <wbr> <wbr> <wbr>test.SetValue();<br>004117DC <wbr> <wbr>lea <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ecx,[test] <wbr><br>004117DF <wbr> <wbr>call <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>CTest::SetValue <wbr>(4111CCh) <wbr></span></div> </div> <div> <wbr> <wbr> <wbr> 同样的,首先把指向对象的指针攑ֈecx寄存器中Q然后调用类CTest的成员函数SetValue()。地址4111CCh那里存放的其实就是一个{x令,转蟩到成员函数SetValue()内部?/div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #000000">004111CC <wbr> <wbr>jmp <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>CTest::SetValue <wbr>(411750h)</span></div> </div> <div> <wbr> <wbr> <wbr> ?11750h才是cCTest的成员函数SetValue()的地址?/div> <div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid"> <div><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> <wbr>CTest::SetValue()<br>{<br></span><span style="COLOR: #000000">00411750</span><span style="COLOR: #000000"> <wbr> <wbr>push <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ebp <wbr> <wbr><br></span><span style="COLOR: #000000">00411751</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ebp,esp <wbr><br></span><span style="COLOR: #000000">00411753</span><span style="COLOR: #000000"> <wbr> <wbr>sub <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>esp,0CCh <wbr><br></span><span style="COLOR: #000000">00411759</span><span style="COLOR: #000000"> <wbr> <wbr>push <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ebx <wbr> <wbr><br>0041175A <wbr> <wbr>push <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>esi <wbr> <wbr><br>0041175B <wbr> <wbr>push <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>edi <wbr> <wbr><br>0041175C <wbr> <wbr>push <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ecx</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>1 <wbr> <wbr> <wbr></span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">0041175D <wbr> <wbr>lea <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>edi,[ebp</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">0CCh] <wbr><br></span><span style="COLOR: #000000">00411763</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ecx,33h <wbr><br></span><span style="COLOR: #000000">00411768</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>eax,0CCCCCCCCh <wbr><br>0041176D <wbr> <wbr>rep <wbr>stos <wbr> <wbr> <wbr> <wbr>dword <wbr>ptr <wbr>es:[edi] <wbr><br>0041176F <wbr> <wbr>pop <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ecx</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>2 <wbr></span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">00411770</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>dword <wbr>ptr <wbr>[ebp</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">],ecx</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>3</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> <wbr> <wbr> <wbr> <wbr>m_iValue1 <wbr></span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #000000">00411773</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>eax,dword <wbr>ptr <wbr>[</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">]</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>4</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">00411776</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>dword <wbr>ptr <wbr>[eax],0Dh</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>5</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"> <wbr> <wbr> <wbr> <wbr>m_iValue2 <wbr></span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> <wbr></span><span style="COLOR: #000000">13</span><span style="COLOR: #000000">;<br>0041177C <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>eax,dword <wbr>ptr <wbr>[</span><span style="COLOR: #0000ff">this</span><span style="COLOR: #000000">]</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>6</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">0041177F <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>dword <wbr>ptr <wbr>[eax</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">],0Dh</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000"> <wbr>7</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">}<br></span><span style="COLOR: #000000">00411786</span><span style="COLOR: #000000"> <wbr> <wbr>pop <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>edi <wbr> <wbr><br></span><span style="COLOR: #000000">00411787</span><span style="COLOR: #000000"> <wbr> <wbr>pop <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>esi <wbr> <wbr><br></span><span style="COLOR: #000000">00411788</span><span style="COLOR: #000000"> <wbr> <wbr>pop <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ebx <wbr> <wbr><br></span><span style="COLOR: #000000">00411789</span><span style="COLOR: #000000"> <wbr> <wbr>mov <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>esp,ebp <wbr><br>0041178B <wbr> <wbr>pop <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>ebp <wbr> <wbr><br>0041178C <wbr> <wbr>ret <wbr></span></div> </div> <div> <wbr> <wbr> <wbr> 下面对上面的汇编代码中的重点行进行分析:<br> <wbr> <wbr> <wbr> 1、将ecx寄存器中的值压栈,也就是把this指针压栈?br> <wbr> <wbr> <wbr> 2、ecx寄存器出栈,也就是this指针出栈?br> <wbr> <wbr> <wbr> 3、将ecx的值放到指定的地方Q也是this指针攑ֈ[ebp-8]内?br> <wbr> <wbr> <wbr> 4、取this指针的值放入eax寄存器内。此Ӟthis指针指向test对象Qtest对象只有两个int型的成员变量Q在test对象内存中连l存放,也就是说this指针目前指向m_iValue1?br> <wbr> <wbr> <wbr> 5、给寄存器eax指向的地址赋?DhQ十六进制的13Q。其实就是给成员变量m_iValue1赋?3?br> <wbr> <wbr> <wbr> 6、同4?br> <wbr> <wbr> <wbr> 7、给寄存器eax指向的地址?的地址赋倹{在4中已l说明,eax寄存器内存放的是this指针Q而this指针指向q箋存放的int型的成员变量m_iValue1。this指针?Qsizeof(int)Q也是成员变量m_iValue2的地址。因此这一行就是给成员变量m_iValue2赋倹{?br> <wbr> <wbr> <wbr> 通过上面的分析,我们可以从底层了解了C++中this指针的实现方法。虽然不同的~译器会使用不同的处理方法,但是C++~译器必遵守C++标准Q因此对于this指针的实现应该都是差不多的?/div> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65372.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:16 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65372.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>引用QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65371.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:15:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65371.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65371.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65371.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65371.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65371.html</trackback:ping><description><![CDATA[<p>----引用的地址Q?/p> <p> <wbr> <wbr> <wbr> ׃引用本n是目标的一个别名,引用本n的地址是一个没有意义的|所以在c++中是无法取得引用的内存地址的。取引用的地址是取目标的地址Qc++本n根本不提供获取引用内存地址的方法?/p> <p> <wbr></p> <p>----引用的赋?/p> <p> <wbr> <wbr> <wbr> 引用一但初始化,׃在能够被指向其它的目标,虽然~译不会出错Q但操作是不起作用的Q实际上q是指向最先指向的目标?br /> int <wbr>a=10; <wbr> <wbr><br /> int <wbr>b=20; <wbr> <wbr><br /> int <wbr>&rn=a; <wbr> <wbr><br /> rn=b;//把引用指向另一个目?---变量b <wbr><br /> 上面代码中的rn=b实际在计机看来是a=bQ所以修改的q是a的倹{?/p> <p> <wbr> <wbr> <wbr> void修饰是不能够声明引用的,<span style="color: #ffff00;"><strong>引用是不能够声明数组?/strong></span>Q即不能够声明引用数l,因ؓ数组是一个由若干个元素所l成的集合,所以无法徏立一个数l的别名?/p> <p> <wbr></p> <p>----q回cL员引用:</p> <p> <wbr> <wbr> <wbr> 可以q回cL员的引用Q但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某U业务规则(business ruleQ相兌的时候,其赋值常怸某些其它属性或者对象的状态有养I因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针)Q那么对该属性的单纯赋值就会破坏业务规则的完整性?/p> <p><br /> ----引用与一些操作符的重载:<br />  <wbr> <wbr> <wbr> 操作符<<?gt;>Q这两个操作W常常希望被q箋使用Q例如:cout << "hello" << endl; 因此q两个操作符的返回值应该是一个仍然支持这两个操作W的引用。可选的其它Ҏ(gu)包括Q返回一个流对象和返回一个流对象指针。但是对于返回一个流对象Q程序必重斎ͼ拯Q构造一个新的流对象Q也是_q箋的两?lt;<操作W实际上是针对不同对象的Q这无法让h接受。对于返回一个流指针则不能连l?lt;<操作W。因此,q回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许q就是C++语言中引入引用这个概늚原因吧?/p> <p> <wbr> <wbr> <wbr> 赋值操作符=Q这个操作符象流操作W一P是可以连l用的Q例如:x = j = 10;或?x=10)=100;赋值操作符的返回值必L一个左|以便可以被l赋倹{因此引用成了这个操作符的惟一q回值选择?/p> <p>#include <iostream.h><br /> int &put(int n);<br /> int vals[10];<br /> int error=-1;<br /> void main()<br /> {<br />  <wbr> <wbr> <wbr> put(0)=10; //以put(0)函数g为左|{h(hun)于vals[0]=10; <wbr><br />  <wbr> <wbr> <wbr> put(9)=20; //以put(9)函数g为左|{h(hun)于vals[9]=10;<br />  <wbr> <wbr> <wbr> cout<<vals[0]; <wbr><br />  <wbr> <wbr> <wbr> cout<<vals[9];<br /> }<br /> int &put(int n)<br /> {<br />  <wbr> <wbr> <wbr> if (n>=0 && n<=9 ) return vals[n];<br />  <wbr> <wbr> <wbr> else { cout<<"subscript error"; return error; }<br /> }</p> <p> <wbr> <wbr> <wbr> <wbr>在另外的一些操作符中,却千万不能返回引用:+-*/ 四则q算W。它们不能返回引用,Effective C++[1]的Item23详细的讨Zq个问题。主要原因是q四个操作符没有side effectQ因此,它们必须构造一个对象作回|可选的Ҏ(gu)包括Q返回一个对象、返回一个局部变量的引用Q返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作ؓq回值的三个规则Q第2?两个Ҏ(gu)都被否决了。静态对象的引用又因?(a+b) == (c+d))会永qؓtrue而导致错误。所以可选的只剩下返回一个对象了?/p> <p> <wbr></p> <p>----引用和多态:<br />  <wbr> <wbr> <wbr> 引用是除指针外另一个可以生多态效果的手段。这意味着Q一个基cȝ引用可以指向它的zcd例?br /> class  A;<br /> class  BQpublic A{……};<br /> B  b;<br /> A  &Ref = b; // 用派生类对象初始化基cd象的引用<br /> Ref 只能用来讉Kzcd象中从基cȝ承下来的成员Q是基类引用指向zcR如果AcM定义有虚函数Qƈ且在BcM重写了这个虚函数Q就可以通过Ref产生多态效果?br /> </p> <p> <wbr></p> <p>----引用与函数返回?/p> <p>1?/p> <p class="code">#include <wbr><iostream> <wbr> <wbr> <wbr><br /> #include <wbr><string> <wbr> <wbr> <wbr><br /> using <wbr>namespace <wbr>std; <wbr> <wbr><br /> <br /> float <wbr>c; <wbr><br /> float <wbr>test(float,float); <wbr><br /> void <wbr>main(int <wbr>argc,char* <wbr>argv[]) <wbr> <wbr> <wbr> <wbr> <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>float <wbr>pn=test(3.0f,1.2f); <wbr><br />  <wbr> <wbr> <wbr> <wbr>cout<<pn; <wbr><br />  <wbr> <wbr> <wbr> <wbr>cin.get(); <wbr><br /> } <wbr><br />  <wbr><br /> float <wbr>test(float <wbr>a,float <wbr>b) <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>c=a*b; <wbr><br />  <wbr> <wbr> <wbr> <wbr>return <wbr>c; <wbr><br /> }</p> <p>  在上面的代码中我们可能以为函数返回的是c变量Q这么想可能错了,普通情况下我们在函数内q行普通D回的时候在内存栈空间内其实是自动生了一个时变量tempQ它是返回值的一个副本一个copyQ函数在return的时候其实是return的这个时生的副本?/p> <p>2、把q回Dl引用:</p> <p class="code">#include <wbr><iostream> <wbr> <wbr> <wbr><br /> #include <wbr><string> <wbr> <wbr> <wbr><br /> using <wbr>namespace <wbr>std; <wbr><br />  <wbr><br /> float <wbr>c; <wbr><br /> float <wbr>test(float,float); <wbr><br /> void <wbr>main(int <wbr>argc,char* <wbr>argv[]) <wbr> <wbr> <wbr> <wbr> <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>float <wbr>&pn=test(3.0f,1.2f);//警告:q回的将是时变?pn引用成Z时变量的别名! <wbr><br />  <wbr> <wbr> <wbr> <wbr>cout<<pn; <wbr><br />  <wbr> <wbr> <wbr> <wbr>cin.get(); <wbr><br /> } <wbr><br />  <wbr><br /> float <wbr>test(float <wbr>a,float <wbr>b) <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>c=a*b; <wbr><br />  <wbr> <wbr> <wbr> <wbr>return <wbr>c; <wbr><br /> }</p> <p>  float &pn=test(3.0f,1.2f);q句在bc中能够编译通过Q因为bc扩展讄Z时变量设|引用,那么临时变量的生命周期将和引用的生命周期一_但在vc中却不能通过~译Q因Z但test()执行q后临时变量消失在栈I间内,q时候pn成Z个没有明目标的引用Q严重的时候会D内存出错?/p> <p>3、返回引用给变量的情况:</p> <p class="code">#include <wbr><iostream> <wbr> <wbr> <wbr><br /> #include <wbr><string> <wbr> <wbr> <wbr><br /> using <wbr>namespace <wbr>std; <wbr><br />  <wbr><br /> <strong>float <wbr>c; </strong><wbr><br /> float& <wbr>test(float,float); <wbr><br /> void <wbr>main(int <wbr>argc,char* <wbr>argv[]) <wbr> <wbr> <wbr> <wbr> <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>float <wbr>pn=test(3.0f,1.2f); <wbr><br />  <wbr> <wbr> <wbr> <wbr>cout<<pn; <wbr><br />  <wbr> <wbr> <wbr> <wbr>cin.get(); <wbr><br /> } <wbr><br />  <wbr><br /> float <wbr>&test(float <wbr>a,float <wbr>b) <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>c=a*b; <wbr><br />  <wbr> <wbr> <wbr> <wbr>return <wbr>c; <wbr><br /> }</p> <p>  q种q回引用l变量的情况下,在内存中Qtest()所在的栈空间内q没有生时变量,而是直接全局变量c的值给了变量pnQ这U方式是我们最为推荐的操作方式Q因Z产生临时变量直接赋值的方式可以节省内存I间提高效率Q程序的可读性也是比较好的。但是仅限于q回的变量是栈中分配的空_或全局变量Q否则返回的依然是时变量。一般对于内|类型,可以使用W一U情늛接返回副本?/p> <p>4、最后的一U情冉|函数q回引用,q且发Dl一个引用的情况Q?/p> <p class="code">#include <wbr><iostream> <wbr> <wbr> <wbr><br /> #include <wbr><string> <wbr> <wbr> <wbr><br /> using <wbr>namespace <wbr>std; <wbr><br />  <wbr><br /> float <wbr>c; <wbr><br /> float& <wbr>test(float,float); <wbr><br /> void <wbr>main(int <wbr>argc,char* <wbr>argv[]) <wbr> <wbr> <wbr> <wbr> <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>float <wbr>&pn=test(3.0f,1.2f); <wbr><br />  <wbr> <wbr> <wbr> <wbr>cout<<pn; <wbr><br />  <wbr> <wbr> <wbr> <wbr>cin.get(); <wbr><br /> } <wbr><br />  <wbr><br /> float <wbr>&test(float <wbr>a,float <wbr>b) <wbr><br /> { <wbr><br />  <wbr> <wbr> <wbr> <wbr>c=a*b; <wbr><br />  <wbr> <wbr> <wbr> <wbr>return <wbr>c; <wbr><br /> }</p> <p>  q种情况同样也不产生临时变量Q可d性能都很好,但有一点容易弄错,是当c是非main的局部变量或者是在堆内存中时开辟后来又被fee掉了以后的区域,q种情况和返回的指针是局部指针的后果一样严重,会导致引用指向了一个不明确的地址?/p> <p>----其他用法Q?/p> <p> <wbr> <wbr> <wbr> 在引用的使用中,单纯l某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中Q解军_块数据或对象的传递效率和I间不如意的问题。用引用传递函数的参数Q能保证参数传递中不生副本,提高传递的效率Q且通过const的用,保证了引用传递的安全性。引用与指针的区别是Q指针通过某个指针变量指向一个对象后Q对它所指向的变量间接操作。程序中使用指针Q程序的可读性差Q而引用本w就是目标变量的别名Q对引用的操作就是对目标变量的操作?/p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65371.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:15 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65371.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言与C++语言的互相调用(C++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65370.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:14:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65370.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65370.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65370.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65370.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65370.html</trackback:ping><description><![CDATA[<p>一、C语言中调用C++函数<br><br>?C++ 函数声明为``extern "C"''Q在你的 C++ 代码里做q个声明Q,然后调用它(在你?C 或?C++ 代码里调用)。例如:</p> <p>// C++ code:</p> <p>extern "C" void f(int);</p> <p>void f(int i)</p> <p>{</p> <p> <wbr> <wbr> <wbr> <wbr> // ...</p> <p>}</p> <p>然后Q你可以q样使用 f()Q?/p> <p> <wbr></p> <p>void f(int);</p> <p>void cc(int i)</p> <p>{</p> <p> <wbr> <wbr> <wbr> f(i);</p> <p> <wbr> <wbr></p> <p>}</p> <p>当然Q这招只适用于非成员函数。如果你惌?C 里调用成员函敎ͼ包括虚函敎ͼQ则需要提供一个简单的包装QwrapperQ。例如:</p> <p>// C++ code:</p> <p>class C</p> <p>{</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> // ...</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> virtual double f(int);</p> <p>};</p> <p>extern "C" double call_C_f(C* p, int i) // wrapper function</p> <p>{</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> return p->f(i);</p> <p>}</p> <p>然后Q你可以这栯?C::f()Q?/p> <p> <wbr></p> <p>double call_C_f(struct C* p, int i);</p> <p>void ccc(struct C* p, int i)</p> <p>{</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> double d = call_C_f(p,i);</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></p> <p>}</p> <p>如果你想?C 里调用重载函敎ͼ则必L供不同名字的包装Q这h能被 C 代码调用。例如:</p> <p>// C++ code:</p> <p>void f(int);</p> <p>void f(double);</p> <p>extern "C" void f_i(int i) { f(i); }</p> <p>extern "C" void f_d(double d) { f(d); }</p> <p>然后Q你可以q样使用每个重蝲?f()Q?/p> <p> <wbr></p> <p>void f_i(int);</p> <p>void f_d(double);</p> <p>void cccc(int i,double d)</p> <p>{</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> f_i(i);</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> f_d(d);</p> <p> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></p> <p>}</p> <p>注意Q这些技巧也适用于在 C 里调?C++ cdQ即使你不能Q或者不惻I修改 C++ 头文件?/p> <p><br>二、C++中调用C函数<br><br>要让你的C代码既能被C代码又能被C++调用虽说Ҏ(gu)Q但是还是有需要注意的地方?/p> <p style="FONT-SIZE: 12pt">现有三个文g分别如下Q?/p> <p style="FONT-SIZE: 12pt">#ifndef TESTC_H<br>#define TESTC_H<br> <br>#ifdef __cplusplus<br>extern "C" {<br>#endif<br> <br>int add(int a, int b);<br>      <br>#ifdef __cplusplus<br>}<br>#endif<br> <br>#endif<br> <br> <br>#include "TestC.h"<br> <br>int add(int a, int b)<br>{<br>    return (a + b);<br>}<br> <br>#include "stdio.h"<br>#include "TestC.h"<br> <br>int main()<br>{<br>       printf("add = %d\n", add(2, 5));<br>      <br>       return 0;<br>}<br> <br>说明Q?br>file TestC.h是C的头文gQfile TestC.c是其实现文gQfile TestCpp.cpp是调用C函数的C++文g?br>文gTestC.h中的TESTC_H定义是ؓ了头文g保护Q?#8221; #ifdef __cplusplus”q个不能~少Q你可以L看C的标准库头文件中都有q个Q如”stdio.h”。有了这个宏~译器就知道现在是Cq是C++在调用它?br>Z么要区分C与C++调用呢?其深层次原因是因为C和C++~译器在~译和链接时对于函数的处理不一栗C++Z支持函数重蝲在编译时会加入函数参数及cd信息。如上面的addҎ(gu)QC~译器编译后在符号库中的名字为_addQ而C++~译器则会生像_add_int_int之类的名字。C++正是依靠q种机制实现了函数的重蝲?br>extern关键字表C将函数或变量声明ؓ全局cdQ与之相对应的是static。static限定函数或变量的作用域ؓ本文件。externq有一个作用就是与”C”q在一起用,即extern “C”通知~译器将extern “C”所包含的代码按照C的方式编译和链接</p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:14 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>unionQC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65368.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:10:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65368.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65368.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65368.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65368.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65368.html</trackback:ping><description><![CDATA[<div id="wjkgbtb" class="articleContent" id="articleBody"> <p>前言<br />  熟?zhn)C的程序员都知道unionQ联合体Q的用法Q利用union可以用相同的存储I间存储不同型别的数据类型,从而节省内存空间。当讉K其内成员时可?."?->"来直接访问。在C++出现后,它承了unionq保留了其在C中的Ҏ(gu)。但是在C++中的union又有了新的扩展,q需要大家了解,要不然你会感到费解和qh。下面我讲两炏V?br /><br />  一、在union中存储对?br />  在C中union中可以存储Q意类型的内置数据cdQ那么在C++中union是否可以存储对象呢?q是让我们看一个例子吧Q这比Q何言语都能说明问题,不是吗?<br />#pragma warning(disable : 4786)<br />#include<br />using namespace std;<br />class TestUnion<br />{<br /> <wbr> <wbr> <wbr> public:<br />  <wbr> TestUnion(long l):data_(l)<br />  <wbr> {<br />  };<br />  <wbr> int data_;<br />};<br />typedef union _tagUtype_<br />{<br />  <wbr> <span style="color: #ffff00;"><strong>TestUnion</strong></span> obj;<br />}UT;<br />int main (void)<br />{<br />  <wbr> return 0;<br />}<br />  q样不行Qunion中不可以存储TestUnioncȝ对象Q但在C中union可以存储struct呀Qؓ什么不能存储类的对象呢Q很单,请问Q在C中union可以存储带有构造函数的struct吗?对了Q在C中的struct是没有构造函数的。所以如果C++中union可以存储有构造函数的cȝ对象׃太符合逻辑Q那不是说C++和C完全兼容吗?不错Q正因ؓq一点,<strong style="color: #ffff00;">C++中union不可以存储有构造函数的cȝ对象</strong>Q但是可以存?strong style="color: #ffff00;">不带构造函?/strong>的类的对象,q样和C保持一致了Q不想信你试试。对TestUnioncȝ声明q行如下修改Q?br />class TestUnion<br />{<br />  <wbr> public:<br />  <wbr> int data_;<br />};<br />  再进行编译,一切OKQ。但是这样却失去了C++的构造初始化Ҏ(gu),q样做是没有M意义的,我只是在说其在C++中的语义Qƈ不是推荐大家使用Q绝对不推荐Q。但是我们可以在union中存储对象的指针Q从而引用不同的对象cd。不用我再多说了吧,大家q是试试吧! </p> <p> <wbr> <wbr> <wbr> 同理Q除了不能加构造函敎ͼ析构函数/拯构造函?赋D符也是不可以加。此外,如果我们的类中包含了Mvirtual函数Q编译时Q我们将收到如下的错误信?<br />  error C2621: union ‘__unnamed‘ : member ‘obj‘ has copy constructor<br />  所以,打消在union中包含有构造函?析构函数/拯构造函?赋D符/虚函数的cȝ对象的念_老老实实用你的<strong style="color: #ffff00;">C风格struct</strong>?<br /><br />二、类中union的初始化<br />  ׃union的共享内存特点,我们可以使我们的cd储不同的型别而不费内存I间Q在cM我们可以声明一个union存储不同型别的指针,CZ如下Q?br />#pragma warning(disable : 4786)<br />#include<br />using namespace std;<br />class TestUnion<br />{<br /> <wbr> <wbr> <wbr> enum StoreType{Long,Const_CharP};<br /> <wbr> <wbr> <wbr> union<br /> <wbr> <wbr> <wbr> {<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> const char* ch_;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> long l_;<br /> <wbr> <wbr> <wbr> <wbr>}data_;<br /> <wbr> <wbr> <wbr> StoreType stype_;</p> <p>public:</p> <p> <wbr> <wbr> <wbr> TestUnion(TestUnion&);<br /> <wbr> <wbr> <wbr> TestUnion& operator=(const TestUnion&);<br /> <wbr> <wbr> <wbr> TestUnion(const char* ch);<br /> <wbr> <wbr> <wbr> TestUnion(long l);<br /> <wbr> <wbr> <wbr> operator const char*() const {return data_.ch_;}<br /> <wbr> <wbr> <wbr> operator long() const {return data_.l_;}<br />};<br />TestUnion::TestUnion(const char* ch):data_.ch_(ch),stype_(Const_CharP)<br />{<br />}<br />TestUnion::TestUnion(long l):data_.l_(l),stype_(Long)<br />{<br />}<br />int main (void)<br />{<br /> <wbr> <wbr> <wbr> TestUnion pszobj("yuankai");<br /> <wbr> <wbr> <wbr> TestUnion lobj(1234);<br /> <wbr> <wbr> <wbr> cout<(pszobj)< cout<<br /> <wbr> <wbr> <wbr> return 0;<br />}<br />真是不幸Q编译都通不q,好象没有什么问题呀Qؓ什么呢Qdata_.ch_(ch)和data_.l_(l)有问题吗Q如果你问一个CE序员他会告诉你Q绝Ҏ(gu)问题。你不会L疑编译器有问题吧Q不好意思!我一开始就是这么想的,真是惭愧。费解,qh。让我们来看看构造TestUnion对象时发生了什么,q样你就会明白了。当创徏TestUnion对象Ӟ自然要调用其相应的构造函敎ͼ在构造函C当然要调用其成员的构造函敎ͼ所以其要去<strong style="color: #ffff00;">调用union成员的构造函敎ͼ但是其ؓ匿名的,有没有构造函数可调用Q所以出?/strong>。很明显在C++中union和class一样它可以有构造函敎ͼ不能如此直接引用其成员。struct同样有这限制。只要我们给其定义一个构造函C么问题都解决了。示例如下:<br /><br />class TestUnion<br />{<br /> <wbr> <wbr> <wbr> enum StoreType{Long,Const_CharP};<br /> <wbr> <wbr> <wbr> union DataUnion //<strong style="color: #ffff00;">不能匿名</strong><br /> <wbr> <wbr> <wbr> <wbr>{<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> DataUnion(const char*); //声明const char*构造函?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> DataUnion(long); //声明long构造函?br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> const char* ch_;<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> long l_;<br /> <wbr> <wbr> <wbr> <wbr> }data_;<br /> <wbr> <wbr> <wbr> <wbr> StoreType stype_;<br />public:<br /> <wbr> <wbr> <wbr> <wbr> TestUnion(TestUnion&);<br /> <wbr> <wbr> <wbr> <wbr> TestUnion& operator=(const TestUnion&);<br /> <wbr> <wbr> <wbr> <wbr> TestUnion(const char* ch);<br /> <wbr> <wbr> <wbr> <wbr> TestUnion(long l);<br /> <wbr> <wbr> <wbr> <wbr> operator const char*() const {return data_.ch_;}<br /> <wbr> <wbr> <wbr> <wbr> <wbr>operator long() const {return data_.l_;}<br />};<br />TestUnion::TestUnion(const char* ch):data_(ch),stype_(Const_CharP)<br />{//注意data_(ch)Q这里直接引用data_<br />}<br />TestUnion::TestUnion(long l):data_(l),stype_(Long)<br />{//注意data_(l)Q这里直接引用data_<br />}<br />TestUnion::DataUnion::DataUnion(const char* ch):ch_(ch)<br />{<br />}<br />TestUnion::DataUnion::DataUnion(long l):l_(l)<br />{<br />}<br /> <wbr> <wbr> <wbr> 不过我更推荐如下的编E风?<br />class TestUnion<br />{<br />  union DataUnion//<span style="color: #ffff00;">其实仅仅是非匿名</span><br />  {<br />   <wbr> <wbr> <wbr> const char* ch_;<br />   <wbr> <wbr> <wbr> long l_;<br />  } data_;<br />public:<br />  TestUnion(const char* ch);<br />  TestUnion(long l);<br />};<br />TestUnion::TestUnion(const char* ch)<br />{<br />  data_.ch_ = ch;<br />}<br />TestUnion::TestUnion(long l)<br />{<br />  data_.l_ = l;<br />}</p> </div><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65368.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:10 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65368.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>随机数生成(C++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65367.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:09:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65367.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65367.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65367.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65367.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65367.html</trackback:ping><description><![CDATA[<div id="zihyaeb" class=articleContent id=articleBody> <p>#include<time.h><br>#include<iostream><br>using namespace std;<br>void main()<br>{<br> <wbr> <wbr> <wbr> int num = 0;<br> <wbr> <wbr> <wbr> <strong><font color=#006600>srand((unsigned)time(NULL));<br></font></strong> <wbr> <wbr> <wbr> for (int i=0; i<10; ++i)<br> <wbr> <wbr> <wbr> {<br> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font color=#006600><strong>num = rand()%10;<br></strong></font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> cout<<num<<endl;<br> <wbr> <wbr> <wbr> }</p> <p>}<br></p> </div> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65367.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:09 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65367.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内置cd最存储空_32位机参考)QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65365.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:02:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65365.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65365.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65365.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65365.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65365.html</trackback:ping><description><![CDATA[<p>bool <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> -</p> <p>char <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>    8bits</p> <p>wchar_t <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> 16bits</p> <p>short <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>    16bitsQ半个机器字长)</p> <p>int <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>      16bitsQ一个机器字长,通常大小32bitsQ?6bits也许是最存储空_</p> <p>long <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>    32bitsQ一或两个机器字长)</p> <p>float <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>     <wbr> 32bitsQ?位有效数字,一般一个机器字长)</p> <p>double <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>  64bitsQ?0位有效数字,一般两个机器字长)</p> <p>long double <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>96?28bitsQ?0位有效数字,一??机器字长Q?/p> <font face=微Y雅黑 color=#8e5f00 size=5></font> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65365.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:02 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65365.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>constQC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65364.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:01:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65364.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65364.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65364.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65364.html</trackback:ping><description><![CDATA[<p><span lang="EN-US" style="font-size: 9pt; font-family: 宋体; mso-bidi-font-family: 宋体; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" xml:lang="EN-US"><font face="Times New Roman"><font size="3">O?/font></font></span></p> <p><font face="Times New Roman" size="3"> <wbr> <wbr> <wbr> <wbr> <wbr></font> <font size="3"><font face="Times New Roman">const int r[ ]={1,2,3,4};<br /> <wbr> <wbr> <wbr> <wbr> <wbr> struct S {int a,b;};<br /> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>const S s[ ]={(1,2),(3.4)}; //</font>以上两种都是帔R集合Q编译器会ؓ其分配内存,所以不能在~译期间使用其中的|例如Q?font face="Times New Roman">int temp[r[2]];</font>q样的编译器会报告不能找到常量表辑ּ?/font></p> <p> <wbr></p> <p><font size="3">一、对于指?/font></p> <p><font face="Times New Roman"><font size="3">1.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font size="3">const int *r=&x; //</font></font><font size="3">声明<font face="Times New Roman">r</font>Z个指向常量的<font face="Times New Roman">x</font>的指针,<font face="Times New Roman">r</font>指向的对象不能被修改Q但他可以指向Q何地址的常量?/font></p> <p><font face="Times New Roman"><font size="3">2.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font size="3">int const *r=&x; //</font></font><font size="3">与用?font face="Times New Roman">1</font>完全{h(hun)Q没有Q何区别?/font></p> <p><font face="Times New Roman"><font size="3">3.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font size="3">int * const r=&x; //</font></font><font size="3">声明<font face="Times New Roman">r</font>Z个常量指针,他指?font face="Times New Roman">x</font>Q?font face="Times New Roman">r</font>q个指针的指向不能被修改Q但他指向的地址的内容可以修攏V?/font></p> <p><font face="Times New Roman"><font size="3">4.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font size="3">const int * const r=&x; //</font></font><font size="3">l合<font face="Times New Roman">1</font>?font face="Times New Roman">3</font>用法Q?font face="Times New Roman">r</font>是一个指向常量的帔R型指针?/font></p> <p> <wbr></p> <p><font size="3">二、对于类型检?/font></p> <p><font size="3"> <wbr> <wbr> <wbr> 可以把一个非<font face="Times New Roman">const</font>对象赋给一个指?font face="Times New Roman">const</font>的指针,因ؓ有时候我们不想从q个指针来修改其对象的|参数传递)Q但是不可以把一?font face="Times New Roman">const</font>对象赋值给一个非<font face="Times New Roman">const</font>指针Q因样可能会通过q个指针改变指向对象的|但也存在使这U操作通过的合法化写法Q用类型强制{换可以通过指针改变<font face="Times New Roman">const</font>对象Q?/font><br /><font face="Times New Roman" size="3">const int r=100;<br />int * ptr = const_cast<int*>(&r); <wbr> //C++</font><font size="3">标准Q?font face="Times New Roman">C</font>语言使用Q?font face="Times New Roman">int * ptr =(int*)&r;Q具体请见强制类型{换的详解Q?/font></font></p> <p> <wbr></p> <font size="3">三、对于字W数l?/font> <p><font size="3"> <wbr> <wbr> <wbr> ?font face="Times New Roman">char * name = “china”;</font> q样的语句,在编译时是能够通过的,但是<font face="Times New Roman">”china”</font>是常量字W数l,M想修改他的操作也能通过~译但会引vq行旉误,如果我们想修改字W数l的话就要?font face="Times New Roman">char name[ ] = “china”;</font> q种形式?/font></p> <p> <wbr></p> <p><font size="3">四、对于函?/font></p> <p><font face="Times New Roman"><font size="3">1.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font size="3">void Fuction1 ( const int r ); //</font></font><font size="3">此处为参C?font face="Times New Roman">const</font>|意义是变量初g能被函数改变?/font></p> <p><font face="Times New Roman"><font size="3">2.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font size="3">const int Fuction1 (int); //</font></font><font size="3">此处q回<font face="Times New Roman">const</font>|意思指q回的原函数里的变量的初g能被修改Q但是函数按D回的q个变量被制成副本,能不能被修改没有了意义Q它可以被赋lQ何的<font face="Times New Roman">const</font>或非<font face="Times New Roman">const</font>cd变量Q完全不需要加上这?font face="Times New Roman">const</font>关键字。但q只对于内部cd而言Q因为内部类型返回的肯定是一个|而不会返回一个变量,不会作ؓ左g用)Q对于用戯定义cdQ返回值是帔R是非帔R要的Q见下面条款<font face="Times New Roman">3</font>?/font></p> <p><font face="Times New Roman"><font size="3">3.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></font></p> <p><font face="Times New Roman"><font size="3">Class CX; //</font></font><font size="3">内部有构造函敎ͼ声明?/font><font size="3"><font face="Times New Roman">CX(int r =0)<br />CX <wbr> Fuction1 () { return CX(); }<br />const CX Fuction2 () { return CX(); }<br /></font>如有上面的自定义c?font face="Times New Roman">CX</font>Q和函数<font face="Times New Roman">Fuction1()</font>?font face="Times New Roman">Fuction2(),</font>我们q行如下操作Ӟ</font><br /><font face="Times New Roman" size="3">Fuction1() = CX(1); //</font><font size="3">没有问题Q可以作为左D?/font><br /><font face="Times New Roman" size="3">Fuction2() = CX(1); //</font><font size="3">~译错误Q?font color="#ff0000"><font face="Times New Roman"><span style="color: #ffff00;">const</span></font><span style="color: #ffff00;">q回值禁止作为左D用,因ؓ左值把q回g为变量会修改其返回|</span><font face="Times New Roman"><span style="color: #ffff00;">const</span></font><span style="color: #ffff00;">声明止q种修改</span></font>?/font></p> <p><font face="Times New Roman"><font size="3">4.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></font> <font size="3">函数中指针的<font face="Times New Roman">const</font>传递和q回Q?/font><br /><font face="Times New Roman" size="3">int F1 (const char * pstr); //</font><font size="3">作ؓ传递的时候?font face="Times New Roman">const</font>修饰可以保证不会通过q个指针来修改传递参数的初|q里在函数内部Q何修?font face="Times New Roman">*pstr</font>的企N会引L译错误?/font><br /><font face="Times New Roman" size="3">const char * F2 (); //</font><font size="3">意义是函数返回的指针指向的对象是一?font face="Times New Roman">const</font>对象Q它必须赋给一个同h指向<font face="Times New Roman">const</font>对象的指针?/font><br /><font face="Times New Roman" size="3">const char * const F3(); //</font><font size="3">比上面多了一?font face="Times New Roman">const</font>Q这?font face="Times New Roman">const</font>的意义只是在他被用作左值时有效Q它表明了这个指针除了指?font face="Times New Roman">const</font>对象外,它本w也不能被修改,所以就不能当作左值来处理?/font></p> <p><font face="Times New Roman"><font size="3">5.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></font> <font size="3">函数中引用的<font face="Times New Roman">const</font>传递:</font><br /><font face="Times New Roman" size="3">void F1 ( const X& px); //</font><font size="3">q样的一?font face="Times New Roman">const</font>引用传递和最普通的函数按g递的效果是一模一LQ他止对引用的对象的一切修改,唯一不同的是按g递会先徏立一个类对象的副本,然后传递过去,而它直接传递地址Q所以这U传递比按g递更有效?/font><br /><font size="3"><font face="Times New Roman"> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></font> 另外只有引用?font face="Times New Roman">const</font>传递可以传递一?strong>临时对象</strong>Q因Z时对象都?font face="Times New Roman">const</font>属性,且是不可见的Q他短时间存在一个局部域中,所以不能用指针,只有引用?font face="Times New Roman">const</font>传递能够捕捉到q个家伙?/font></p> <p> <wbr></p> <p><font size="3">五?/font><font style="font-size: 16px">对于c?/font></p> <p><font face="Times New Roman"><font size="3">1.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></font> <font size="3">首先Q对?font face="Times New Roman">const</font>的成员变量,只能在构造函数里使用初始化成员列表来初始化,试图在构造函C内进行初始化<font face="Times New Roman">const</font>成员变量会引L译错误。初始化成员列表形如Q?/font><br /><font face="Times New Roman" size="3">X:: X ( int ir ): r(ir) {} //</font><font size="3">假设<font face="Times New Roman">r</font>是类<font face="Times New Roman">X</font>?font face="Times New Roman">const</font>成员变量</font></p> <p><font face="Times New Roman"><font size="3">2.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <font size="3">const</font></font><font size="3">成员函数。提到这个概念首先要谈到cȝ<font face="Times New Roman">const</font>对象Q正像内|类型能够定?font face="Times New Roman">const</font>对象一P<font face="Times New Roman">const int r=10;</font>Q,用户自定义类型也可以定义<font face="Times New Roman">const</font>对象<font face="Times New Roman">(const X px(10);)</font>Q编译器要保证这个对象在其生命周期内不能够被改变。如果你定义了这L一?font face="Times New Roman">const</font>对象Q那?/font><span style="font-size: medium;">~译器ؓ了保证对象的</span><font face="Times New Roman" style="font-size: medium;">const</font><span style="font-size: medium;">Ҏ(gu),</span><font size="3"><span style="color: #ffff00;">对于q个对象的一切非</span><font face="Times New Roman"><span style="color: #ffff00;">const</span></font><span style="color: #ffff00;">成员函数的调?/span>都会被禁止ƈ在编译期间报错(除构造函数和析构函数Q。所以如果你惌你的成员函数能够?font face="Times New Roman">const</font>对象上进行操作的话,p把这个函数声明ؓ<font face="Times New Roman">const</font>成员函数?br /></font>      <font size="3">假如<font face="Times New Roman">f( )</font>是类中的成员函数的话Q它的声明Ş如:<br /></font><font face="Times New Roman" size="3">int f( ) const; //const</font><font size="3">攑֜函数的最?br />~译器会对这个函数进行检查,在这个函C的Q何试图改变成员变量和调用?font face="Times New Roman">const</font>成员函数的操作都被视为非法?/font><font size="3">cȝ构造和析构函数都不能是<font face="Times New Roman">const</font>函数?/font></p> <p><font face="Times New Roman"><font size="3">3.</font> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr></font> <font size="3">建立了一?font face="Times New Roman">const</font>成员函数Q但仍然想用q个函数改变对象内部的数据,q样的要求也会经帔R刎ͼ其是在一个苛ȝ面试考官那里。首先我们要弄清楚考官的要求,因ؓ有两U方法可以实玎ͼ如果q位考官要求不改变原来类的Q何东西,只让你从当前q个<font face="Times New Roman">const</font>成员函数入手Q那么你只有使用前面提到的类型强制{换方法。实例如下:</font><br /><font face="Times New Roman" size="3">//</font><font size="3">假如有一个叫?font face="Times New Roman">X</font>的类Q它有一?font face="Times New Roman">int</font>成员变量<font face="Times New Roman">r</font>Q我们需要通过一?font face="Times New Roman">const</font>成员函数<font face="Times New Roman">f( )</font>来对q个<font face="Times New Roman">r</font>q行<font face="Times New Roman">++r</font>操作Q代码如?/font><br /><font face="Times New Roman" size="3">void X::f( ) const<br />{ <wbr> (const_cast<X*>(this)) -> ++r;  <wbr>} //</font><font size="3">通过<font face="Times New Roman">this</font>指针q行cd强制转换实现</font><br /><font size="3">另外一U方法就是用关键字Q?strong><font face="Times New Roman">mutable</font></strong><strong>?/strong>如果你的成员变量在定义时是这个样子的Q?/font><br /><font face="Times New Roman" size="3">mutable int r ;<br /></font><font size="3">那么它就告诉~译器这个成员变量可以通过<font face="Times New Roman">const</font>成员函数改变。编译器׃会再理会对他的检查了?/font></p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:01 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title># 预处理预~译QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65363.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 12:00:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65363.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65363.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65363.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65363.html</trackback:ping><description><![CDATA[<p>一、预处理的由来:<br> <wbr> <wbr> <wbr> 在C++的历史发展中Q有很多的语a特征Q特别是语言的晦涩之处)来自于C语言Q预处理是其中的一个。C++从C语言那里把C语言预处理器Q被Bjarne博士UCؓCppQ不知道是不是C Program Preprocessor的简Uͼl承q来?/p> <p><br>二、常见的预处理功能:<br> <wbr> <wbr> <wbr> 预处理器的主要作用就是把通过预处理的内徏功能对一个资源进行等h换,最常见的预处理有:文g包含Q条件编译、布局控制和宏替换4U?/p> <p> <wbr> <wbr> <wbr> 文g包含Q?/p> <p>#include 是一U最为常见的预处理,主要是做为文件的引用l合源程序正文?br> <wbr> <wbr> <wbr> 条g~译Q?/p> <p>#ifQ?ifndefQ?ifdefQ?endifQ?undef{也是比较常见的预处理,主要是进行编译时q行有选择的挑选,注释掉一些指定的代码Q以辑ֈ版本控制、防止对文g重复包含的功能?/p> <p> <wbr> <wbr> <wbr> 布局控制Q?/p> <p>#progmaQ这也是我们应用预处理的一个重要方面,主要功能是ؓ~译E序提供非常规的控制信息?br> <wbr> <wbr> <wbr> 宏替换:</p> <p>#defineQ这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字W串的拼接等各种功能?/p> <p><br>三、预处理指oQ?br> <wbr> <wbr> <wbr> 预处理指令的格式如下Q?br>#directive tokens<br>#W号应该是这一行的W一个非I字W,一般我们把它放在v始位|。如果指令一行放不下Q可以通过q行控制Q例如:<br>#define Error if(error) exit(1)</p> <p>{h(hun)?br>#define Error<br>if(error) exit(1)<br>不过我们Z化赯Q一般都不怎么q么用,更常见的方式如下Q?br># ifdef __BORLANDC__<br>if_true<(is_convertible<Value,named_template_param_base>::value)>::<br>template then<make_named_arg, make_key_value>::type Make;<br># else<br>enum { is_named = is_named_parameter<Value>::value };<br>typedef typename if_true<(is_named)>::template<br>then<make_named_arg, make_key_value>::type Make;<br># endif<br>下面我们看一下常见的预处理指令:<br>#define 宏定?br>#undef 未定义宏<br>#include 文本包含<br>#ifdef 如果宏被定义p行编?br>#ifndef 如果宏未被定义就q行~译<br>#endif l束~译块的控制<br>#if 表达式非零就对代码进行编?br>#else 作ؓ其他预处理的剩余选项q行~译<br>#elif q是一U?else?if的组合选项<br>#line 改变当前的行数和文g名称<br>#error 输出一个错误信?br>#pragma 为编译程序提供非常规的控制流信息<br> <wbr> <wbr> <wbr> 下面我们对这些预处理q行一一的说明,考虑到宏的重要性和J琐性,我们把它攑ֈ最后讲?br><br>四、文件包含指令: #include<br>q种预处理用方式是最为常见的Q^时我们编写程序都会用刎ͼ最常见的用法是Q?br>#include <iostream> //标准库头文g<br>#include <iostream.h> //旧式的标准库头文?br>#include "IO.h" //用户自定义的头文?br>#include "../file.h" //UNIX下的父目录下的头文g<br>#include "/usr/local/file.h" //UNIX下的完整路径<br>#include "..file.h" //Dos下的父目录下的头文g<br>#include "usrlocalfile.h" //Dos下的完整路径<br>q里面有2个地方要注意Q?br>1、我们用<iostream>q是<iostream.h>?<br>我们d使用<iostream>Q而不?lt;iostream.h>,Z么呢Q我想你可能q记得我曄l出q几点理由,q里我大致的说一下:首先Q?h格式的头文g早在98q?月䆾p标准委员会抛弃了Q我们应该紧跟标准,以适合时代的发展。其ơ,iostream.h只支持窄字符集,iostream则支持窄/宽字W集。还有,标准对iostream作了很多的改动,接口和实现都有了变化。最后,iostreamlg全部攑օnamespace std中,防止了名字污染?br>2?lt;io.h>?io.h"的区别?<br>其实他们唯一的区别就是搜索\径不同:<br>对于#include <io.h> Q编译器从标准库路径开始搜?br>对于#include "io.h" Q编译器从用L工作路径开始搜?br><br>五、编译控制指令:<br>q些指o的主要目的是q行~译时进行有选择的挑选,注释掉一些指定的代码Q以辑ֈ版本控制、防止对文g重复包含的功能。用格式,如下Q?br>1、如果identifierZ个定义了的符Pyour code׃被编译,否则剔除<br>#ifdef identifier<br>your code<br>#endif<br>2、如果identifierZ个未定义的符Pyour code׃被编译,否则剔除<br>#ifndef identifier<br>your code<br>#endif<br>3、如果expression非零Qyour code׃被编译,否则剔除<br>#if expression<br>your code<br>#endif<br>4、如果identifierZ个定义了的符Pyour code1׃被编译,否则your code2׃被编?br>#ifdef identifier<br>your code1<br>#else<br>your code2<br>#endif<br>5、如果epression1非零Q就~译your code1Q否则,如果expression2非零Q就~译your code2Q否则,q译your code3<br>#if expressin1<br>your code1<br>#elif expression2 //呵呵Qelif<br>your code2<br>#else<br>your code3<br>#enif<br><br>六、其他预~译指o<br> <wbr> <wbr> <wbr> 除了上面我们说的集中常用的编译指令,q有3U不太常见的~译指oQ?line?error?pragmaQ我们接下来q单的谈一下?br>1?line的语法如下:<br>#line number filename<br>例如Q?line 30 a.h 其中Q文件名a.h可以省略不写?/p> <p>q条指o可以改变当前的行号和文g名,例如上面的这条预处理指o可以改变当前的行号?0Q文件名是a.h。初看v来似乎没有什么用Q不q,他还是有点用的,那就是用在编译器的编写中Q我们知道编译器对C++源码~译q程中会产生一些中间文Ӟ通过q条指oQ可以保证文件名是固定的Q不会被q些中间文g代替Q有利于q行分析?br>2?error语法如下Q?br>#error info<br>例如Q?/p> <p>#ifndef UNIX<br>#error This software requires the UNIX OS.<br>#endif<br>q条指o主要是给出错误信息,上面的这个例子就是,如果没有在UNIX环境下,׃输出This software requires the UNIX OS.然后诱发~译器终止。所以ȝ来说Q这条指令的目的是在程序崩溃之前能够给Z定的信息?br>3?pragma</p> <p>它是非统一的,他要依靠各个~译器生产者,例如Q在SUN C++~译器中Q?br>// 把name和val的v始地址调整?个字节的倍数<br>#progma align 8 (name, val)<br>char name[9];<br>double val;</p> <p>或是如下用法Q?br>//在程序执行开始,调用函数MyFunction<br>#progma init (MyFunction)</p> <p><br>七、预定义标识W?br>Z处理一些有用的信息Q预处理定义了一些预处理标识W,虽然各种~译器的预处理标识符不尽相同Q但是他们都会处理下面的4U:<br>__FILE__ 正在~译的文件的名字<br>__LINE__ 正在~译的文件的行号<br>__DATE__ ~译时刻的日期字W串Q例如: "25 Dec 2000"<br>__TIME__ ~译时刻的时间字W串Q例如: "12:30:55"<br>例如Qcout<<"The file is :"<<__FILE__"<<"! The lines is:"<<__LINE__<<endl;</p> <p><br>八、预处理何去何从<br> <wbr> <wbr> <wbr> 如何取代#include预处理指令,我们在这里就不再一一讨论了。C++q没有ؓ#include提供替代形式Q但是namespace提供了一U作用域机制Q它能以某种方式支持l合Q利用它可以改善#include的行为方式,但是我们q是无法取代#include?br> <wbr> <wbr> <wbr> #progma应该是一个可有可无的预处理指令,按照C++之父Bjarne的话_是Q?#progma被过分的l常的用于将语言语义的变形隐藏到~译pȝ里,或者被用于提供带有Ҏ(gu)语义和笨拙语法的语言扩充?#8221;<br> <wbr> <wbr> <wbr> 对于#ifdefQ我们仍然束手无{,q是我们利用if语句和常量表辑ּQ仍然不以替代她,因ؓ一个if语句的正文必d语法上正,满cL查,即他处在一个绝不会被执行的分支里面?/p> <img src ="http://www.shnenglu.com/zmllegtui/aggbug/65363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 20:00 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>explicit 和类的{换(C++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65362.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 11:59:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65362.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65362.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65362.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65362.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65362.html</trackback:ping><description><![CDATA[<p>// explicit关键?/p> <p>    c++中的explicit关键字用来修饰类的构造函敎ͼ表明该构造函数是昑ּ的,xl构造时的隐式{换。如果c++cȝ构造函数有一个参敎ͼ那么在编译的时候就会有一个缺省的转换操作Q将该构造函数对应数据类型的数据转换cd象,如下面所C:</p> <p>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所谓的"隐式转换"?/p> <p>    如果要避免这U自动{换的功能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 />// 隐式cȝ型{?br /> <br />    q种效果一般都是通过cL造函数实现的。那些可以用单个实参来调用的构造函敎ͼ定义了从形参cd到该cȝ型的一个隐式{换。例如如下情况:<br />xxx(valueOfType1);//对于接受ClassTypecd参数的函数xxxQ参C递中执行了隐式{换?br />xxx(ClassType(valueOfType1));//与上面一句效果相同,只是昄的用了对应的构造函数?br />    另外需要注意上面两个语句中传递的cȝ型参数的生命周期仅限制在xxx函数中?br />    如果需要抑制这U由构造函数定义的隐式转换Q可以如上面所说将构造函数声明ؓexplicitQ且仅用于声明)?br /> <br />// 从类cd的{?br />    与隐式类cd转换不同Q前者是到类cd的{换,而现在是利用<strong style="color: #ffff00;">转换操作W?/strong>Qɾl定cȝ型的对象转换成ؓ其他cd对象。这U{换ؓ什么有用呢Q这U方法ؓ了ɾcL持؜合类型表辑ּQ且可以减少c需要的支持功能的操作符数目。定义方法:通用形式?operator type();<br />class A<br />{<br />public:<br />    A()<br />    {<br />        ……<br />    }<br />    operator B() const<br />    {<br />        return AtoB(A());<br />    }<br />    ……<br />};<br />    转换函数一般不应该改变被{换的对象Q因此{换操作符通常应该定义为const?br /> <br />// Reference<br />    详情误《C++ Primer?th Edi中的5.12?2.4?4.9Q还有google资源?/p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65362.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 19:59 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65362.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存I间分配QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65331.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 07:05:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65331.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65331.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65331.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65331.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65331.html</trackback:ping><description><![CDATA[     摘要: 在C++中,内存分成5个区Q他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区?<br>栈,是那些q译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等? <br>堆,是那些由new分配的内存块Q他们的释放~译器不ȝQ由我们的应用程序去控制Q一般一个newp对应一个delete。如果程序员没有释放掉,那么在程序结束后Q操作系l会自动回收?<br>…?<br> <br> <br>  <a href='http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65331.html'>阅读全文</a><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65331.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 15:05 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65331.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>虚析构函敎ͼC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65328.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 06:46:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65328.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65328.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65328.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65328.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65328.html</trackback:ping><description><![CDATA[     摘要: 我们知道Q用C++开发的时候,用来做基cȝcȝ析构函数一般都是虚函数。可是,Z么要q样做呢Q下面用一个小例子来说明: <br>有下面的两个c: <br>class ClxBase <br>{ <br>public: <br>…?<br> <br>  <a href='http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65328.html'>阅读全文</a><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65328.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 14:46 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65328.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>auto_ptrQC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65323.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 06:29:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65323.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65323.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65323.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65323.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65323.html</trackback:ping><description><![CDATA[     摘要: 很多人听说过标准auto_ptr指针机制Q但q不是每个h都天天用它。这真是个遗憾,因ؓauto_ptr优雅地解决了C++设计和编码中常见的问题,正确C用它可以生成健壮的代码。本文阐qC如何正确q用auto_ptr来让你的代码更加安全——以及如何避免对auto_ptr危险但常见的误用Q这些误用会引发间断性发作、难以诊断的bug?<br>…?<br> <br>  <a href='http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65323.html'>阅读全文</a><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65323.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 14:29 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65323.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TempleteQC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65316.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Tue, 28 Oct 2008 05:46:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65316.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65316.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65316.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65316.html</trackback:ping><description><![CDATA[     摘要: 一、什么是模板 <br> 模板是根据参数类型生成函数和cȝ机制Q有时称为“参数决定类型”)。通过使用模板Q可以只设计一个类来处理多U类型的数据Q而不必ؓ每一U类型分别创建类?<br> 例如Q创Z个类型安全函数来q回两个参数中较?yu)的一个,如果不用TemplatesQ必要~写一pd如下的函敎ͼ <br>…?<br> <br>  <a href='http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65316.html'>阅读全文</a><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-28 13:46 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/28/65316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>STL std::string的内存共享和Copy-On-Write技术(C++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65255.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Mon, 27 Oct 2008 14:56:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65255.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65255.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65255.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65255.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65255.html</trackback:ping><description><![CDATA[<span>1</span><span>、概?/span><span><br /></span>      <span>Scott Meyers</span><span>在?/span><span>More Effective C++</span><span>》中举了个例子,不知你是否还记得Q在你还在上学的时候,你的父母要你不要看电视,而去复习功课Q于是你把自己关在房间里Q做Z副正在复习功评样子Q其实你在干着别的诸如l班上的某位女生写情书之cȝ事,而一旦你的父母出来在你房间要查你是否在复习时Q你才真正捡赯本看书。这是</span><span>“</span><span>拖g战术</span><span>”</span><span>Q直C非要做的时候才d?/span><span><br /></span>      <span>当然Q这U事情在现实生活中时往往会出事,但其在编E世界中摇n一变,成Z最有用的技术,正如</span><span>C++</span><span>中的可以随处声明变量的特点一P</span><span>Scott Meyers</span><span>推荐我们Q在真正需要一个存储空间时才去声明变量Q分配内存)Q这样会得到E序在运行时最的内存花销。执行到那才会去做分配内存这U比较耗时的工作,q会l我们的E序在运行时有比较好的性能。必竟,</span><span>20%</span><span>的程序运行了</span><span>80%</span><span>的时间?/span><span> <span><br /></span></span>      <span>当然Q拖延战术还q不只是q样一U类型,q种技术被我们q泛地应用着Q特别是在操作系l当中,当一个程序运行结束时Q操作系lƈ不会急着把其清除出内存,原因是有可能E序q会马上再运行一ơ(从磁盘把E序装入到内存是个很慢的q程Q,而只有当内存不够用了Q才会把q些q驻留内存的E序清出?/span><span><br /></span>      <span>写时才拷贝(</span><span>Copy-On-Write</span><span>Q技术,是~程?/span><span>“</span><span>懒惰行ؓ</span><span>”——</span><span>拖g战术的物。D个例子,比如我们有个E序要写文gQ不断地Ҏ(gu)|络传来的数据写Q如果每一?/span><span>fwrite</span><span>或是</span><span>fprintf</span><span>都要q行一个磁盘的</span><span>I/O</span><span>操作的话Q都直就是性能上巨大的损失Q因此通常的做法是Q每ơ写文g操作都写在特定大的一块内存中Q磁盘缓存)Q只有当我们关闭文gӞ才写到磁盘上Q这是Z么如果文件不关闭Q所写的东西会丢q原因Q。更有甚者是文g关闭旉不写盘Q而一直等到关机或是内存不够时才写盘Q?/span><span>Unix</span><span>是q样一个系l,如果非正帔R出,那么数据׃丢失Q文件就会损坏?/span><span>Z性能我们需要冒q样大的风险Q还好我们的E序是不会忙得忘了还有一块数据需要写到磁盘上的,所以这U做法,q是很有必要的?br /></span><span><br />2</span><span>?/span><span>标准</span><span>C++</span><span>c?/span><span>std::string</span><span>?/span><span>Copy-On-Write<br /></span><span>      在我们经怋用的</span><span>STL</span><span>标准模板库中?/span><span>string</span><span>c,也是一个具有写时才拯技术的cR?/span><span>C++</span><span>曑֜性能问题上被q泛地质疑和指责q,Z提高性能Q?/span><span>STL</span><span>中的许多c都采用?/span><span>Copy-On-Write</span><span>技术。这U偷懒的行ؓ的确使?/span><span>STL</span><span>的程序有着比较高要性能?/span><span><br /></span><span>q里Q我想从</span><span>C++</span><span>cL是设计模式的角度为各位揭开</span><span>Copy-On-Write</span><span>技术在</span><span>string</span><span>中实现的面纱Q以供各位在?/span><span>C++</span><span>q行cd设计时做一点参考?/span><span><br /></span><span>在讲q这Ҏ(gu)术之前,我想单地说明一?/span><span>string</span><span>cd存分配的概念。通过常,</span><span>string</span><span>cM必有一个私有成员,其是一?/span><span>char*</span><span>Q用戯录从堆上分配内存的地址Q其在构造时分配内存Q在析构旉攑ֆ存。因为是从堆上分配内存,所?/span><span>string</span><span>cdl护q块内存上是格外心的,</span><span>string</span><span>cdq回q块内存地址Ӟ只返?/span><span>const char*</span><span>Q也是只读的,如果你要写,你只能通过</span><span>string</span><span>提供的方法进行数据的改写?br /></span><span><br />2.1</span><span>?/span><span>Ҏ(gu)?/span><span><br /></span><span>      p及里Q由感性到理性,我们先来看一?/span><span>string</span><span>cȝ</span><span>Copy-On-Write</span><span>的表面特征。让我们写下下面的一D늨序:</span><span><br />#include<br />#include <br />using namespace std;<br />main()<br />{<br />     string str1 = "hello world";<br />     string str2 = str1; <br />     printf ("Sharing the memory:\n");<br />     printf ("\tstr1's address: %x\n", str1.c_str() );<br />     printf ("\tstr2's address: %x\n", str2.c_str() );     <br />  <span>  </span>str1[1]='q';<br />     str2[1]='w'; <br />     printf ("After Copy-On-Write:\n");<br />     printf ("\tstr1's address: %x\n", str1.c_str() );<br />     printf ("\tstr2's address: %x\n", str2.c_str() ); <br />     return 0;<br />}       <br /></span><span>      q个E序的意囑ְ是让W二?/span><span>string</span><span>通过W一?/span><span>string</span><span>构造,然后打印出其存放数据的内存地址Q然后分别修?/span><span>str1</span><span>?/span><span>str2</span><span>的内容,再查一下其存放内存的地址。程序的输出是这LQ我?/span><span>VC6.0</span><span>?/span><span>g++ 2.95</span><span>都得C同样的结果)Q?/span><span><br />> g++ -o stringTest stringTest.cpp<br />> ./stringTest<br />Sharing the memory:<br />    str1's address: 343be9<br />    str2's address: 343be9<br />After Copy-On-Write:<br />    str1's address: 3407a9<br />    str2's address: 343be9       <br /></span><span>从结果中我们可以看到Q在开始的两个语句后,</span><span>str1</span><span>?/span><span>str2</span><span>存放数据的地址是一LQ而在修改内容后,</span><span>str1</span><span>的地址发生了变化,?/span><span>str2</span><span>的地址q是原来的。从q个例子Q我们可以看?/span><span>string</span><span>cȝ</span><span>Copy-On-Write</span><span>技术?/span><span><br /><br />2.2</span><span>?/span><span>深入</span><span><br /></span><span>      在深入这前,通过上述的演C,我们应该知道?/span><span>string</span><span>cMQ要实现写时才拷贝,需要解决两个问题,一个是内存׃nQ一个是</span><span>Copy-On-Wirte</span><span>Q这两个主题会让我们产生许多疑问Q还是让我们带着q样几个问题来学习吧Q?/span><span><br />1</span><span>?/span><span> Copy-On-Write</span><span>的原理是什么?</span><span><br />2</span><span>?/span><span> string</span><span>cd什么情况下才共享内存的Q?/span><span><br />3</span><span>?/span><span> string</span><span>cd什么情况下触发写时才拷贝(</span><span>Copy-On-Write</span><span>Q?/span><span>?<br />4</span><span>?/span><span> Copy-On-Write</span><span>Ӟ发生了什么?</span><span><br />5</span><span>?/span><span> Copy-On-Write</span><span>的具体实现是怎么LQ?/span><span><br /></span><span>      喔,你说只要看一?/span><span>STL</span><span>?/span><span>stirng</span><span>的源码你可以找到答案了。当Ӟ当然Q我也是参考了</span><span>string</span><span>的父模板c?/span><span>basic_string</span><span>的源码。但是,如果你感到看</span><span>STL</span><span>的源码就好像看机器码Qƈ严重打击你对</span><span>C++</span><span>自信心,乃至产生了自己是否懂</span><span>C++</span><span>的疑问,如果你有q样的感觉,那么q是l箋往下看我的q篇文章吧?/span><span><br />OK</span><span>Q让我们一个问题一个问题地探讨吧,慢慢地所有的技术细节都会Q出水面的?br /></span><span><br />2.3</span><span>?/span><span>Copy-On-Write</span><span>的原理是什么?</span><span><br /><br /></span><span>      有一定经验的E序员一定知道,</span><span>Copy-On-Write</span><span>一定用了</span><span>“</span><span>引用计数</span><span>”</span><span>Q是的,必然有一变量cM?/span><span>RefCnt</span><span>。当W一个类构造时Q?/span><span>string</span><span>的构造函CҎ(gu)传入的参C堆上分配内存Q当有其它类需要这块内存时Q这个计Cؓ自动累加Q当有类析构Ӟq个计数会减一Q直到最后一个类析构Ӟ此时?/span><span>RefCnt</span><span>?/span><span>1</span><span>或是</span><span>0</span><span>Q此ӞE序才会真正?/span><span>Free</span><span>q块从堆上分配的内存?/span><span><br /></span><span>是的Q引用计数就?/span><span>string</span><span>cM写时才拷贝的原理Q?/span><span><br /></span><span>      不过Q问题又来了Q这?/span><span>RefCnt</span><span>该存在在哪里呢?如果存放?/span><span>string</span><span>cMQ那么每?/span><span>string</span><span>的实例都有各自的一套,Ҏ(gu)不能共有一?/span><span>RefCnt</span><span>Q如果是声明成全局变量Q或是静态成员,那就是所有的</span><span>string</span><span>cd享一个了Q这也不行,我们需要的是一?/span><span>“</span><span>民主和集?/span><span>”</span><span>的一个解x法。这是如何做到的呢?呵呵Qh生就是一个糊涂后L知,知道后和又糊涂的循环q程。别急别急,在后面我会给你一一道来的?/span><span><br /><br />2.3.1</span><span>?/span><span>string</span><span>cd什么情况下才共享内存的Q?/span><span><br /></span><span>      q个问题的答案应该是明显的,Ҏ(gu)常理和逻辑Q如果一个类要用另一个类的数据,那就可以׃n被用类的内存了。这是很合理的,如果你不用我的,那就不用׃nQ只有你使用我的Q才发生׃n?/span><span><br /></span><span>      使用别的cȝ数据Ӟ无非有两U情况,</span><span>1</span><span>Q以别的cL造自己,</span><span>2</span><span>Q以别的c赋倹{第一U情冉|会触发拷贝构造函敎ͼW二U情况会触发赋值操作符。这两种情况我们都可以在cM实现其对应的Ҏ(gu)。对于第一U情况,只需要在</span><span>string</span><span>cȝ拯构造函C做点处理Q让其引用计数篏加;同样Q对于第二种情况Q只需要重?/span><span>string</span><span>cȝ赋值操作符Q同样在其中加上一点处理?/span><span><br /></span><span>      唠叨几句Q?/span><span><br />1</span><span>Q构造和赋值的差别</span><span><br /></span><span>对于前面那个例程中的q两句:</span><span><br />     string str1 = "hello world";<br />     string str2 = str1;<br /></span><span>不要以ؓ?/span><span>“=”</span><span>是赋值操作,其实Q这两条语句{h(hun)于:</span><span><br />     string str1 ("hello world");   //</span><span>调用的是构造函?/span><span><br />     string str2 (str1);         //</span><span>调用的是拯构造函?/span><span><br /></span><span>如果</span><span>str2</span><span>是下面的q样情况Q?/span><span><br />string str2;     //</span><span>调用参数默认为空串的构造函敎ͼ</span><span>string str2(“”);<br />str2 = str1;   //</span><span>调用</span><span>str2</span><span>的赋值操作:</span><span>str2.operator=(str1);<br />2) </span><span>另一U情?/span><span><br />     char tmp[]=”hello world”;<br />     string str1 = tmp;<br />     string str2 = tmp;<br /></span><span>q种情况下会触发内存的共享吗Q想当然的,应该要共享。可是根据我们前面所说的׃n内存的情况,两个</span><span>string</span><span>cȝ声明和初始语句ƈ不符合我前述的两U情况,所以其q不发生内存׃n。而且Q?/span><span>C++</span><span>现有Ҏ(gu)也无法让我们做到对q种情况q行cȝ内存׃n?/span><span><br />      <br />2.3.2</span><span>?/span><span>string</span><span>cd什么情况下触发写时才拷贝(</span><span>Copy-On-Write</span><span>Q?/span><span>?<br /></span><span>      哦,什么时候会发现写时才拷贝?很显Ӟ当然是在׃n同一块内存的cd生内Ҏ(gu)变时Q才会发?/span><span>Copy-On-Write</span><span>。比?/span><span>string</span><span>cȝ</span><span>[]</span><span>?/span><span>=</span><span>?/span><span>+=</span><span>?/span><span>+</span><span>、操作符赋|q有一?/span><span>string</span><span>cM诸如</span><span>insert</span><span>?/span><span>replace</span><span>?/span><span>append</span><span>{成员函数?/span><span><br /></span><span>      修改数据才会触发</span><span>Copy-On-Write</span><span>Q不修改当然׃会改啦。这是托g战术的真谛,非到要做的时候才d?br /></span><span><br />2.3.3</span><span>?/span><span>Copy-On-Write</span><span>Ӟ发生了什么?</span><span><br /></span><span>      我们可能Ҏ(gu)那个讉K计数来决定是否需要拷贝,参看下面的代码:</span><span><br />If ( RefCnt>0 ) {<br />  char* tmp = (char*) malloc(strlen(_Ptr)+1);<br />  strcpy(tmp, _Ptr);<br />  _Ptr = tmp;<br />}<br /></span><span>      上面的代码是一个假想的拯Ҏ(gu)Q如果有别的cd引用Q检查引用计数来LQ这块内存,那么需要把更改c进?/span><span>“</span><span>拯</span><span>”</span><span>q个动作?/span><span><br /></span><span>我们可以把这个拷的运行封装成一个函敎ͼ供那些改变内容的成员函数使用?br /></span><span><br />2.3.4</span><span>?/span><span>Copy-On-Write</span><span>的具体实现是怎么LQ?/span> <p><span>      最后的q个问题Q我们主要解决的是那?/span><span>“</span><span>民主集中</span><span>”</span><span>的难题。请先看下面的代码:</span><span><br />string h1 = “hello”;<br />string h2= h1;<br />string h3;<br />h3 = h2;<br />string w1 = “world”;<br />string w2(“”);<br />w2=w1;       <br /></span><span>      很明显,我们要让</span><span>h1</span><span>?/span><span>h2</span><span>?/span><span>h3</span><span>׃n同一块内存,?/span><span>w1</span><span>?/span><span>w2</span><span>׃n同一块内存。因为,?/span><span>h1</span><span>?/span><span>h2</span><span>?/span><span>h3</span><span>中,我们要维护一个引用计敎ͼ?/span><span>w1</span><span>?/span><span>w2</span><span>中我们又要维护一个引用计数?/span><span><br /></span><span>      如何使用一个y妙的Ҏ(gu)产生q两个引用计数呢Q我们想C</span><span>string</span><span>cȝ内存是在堆上动态分配的Q既然共享内存的各个cL向的是同一个内存区Q我们ؓ什么不在这块区上多分配一点空间来存放q个引用计数呢?q样一来,所有共享一块内存区的类都有同样的一个引用计敎ͼ而这个变量的地址既然是在׃nZ的,那么所有共享这块内存的c都可以讉K刎ͼ也就知道q块内存的引用者有多少了?/span><span><br /></span><span><br /></span><span>      于是Q有了这样一个机Ӟ每当我们?/span><span>string</span><span>分配内存Ӟ我们L要多分配一个空间用来存放这个引用计数的|只要发生拯构造或是赋值时Q这个内存的值就会加一。而在内容修改Ӟ</span><span>string</span><span>cMؓ查看q个引用计数是否?/span><span>0</span><span>Q如果不为零Q表C有人在׃nq块内存Q那么自己需要先做一份拷贝,然后把引用计数减MQ再把数据拷贝过来。下面的几个E序片段说明了这两个动作Q?/span><span><br /> //</span><span>构造函敎ͼ分存内存Q?/span><span> <br />  string::string(const char* tmp)<br />{<br />  _Len = strlen(tmp);<br />  _Ptr = new char[_Len+1+1];<br />  strcpy( _Ptr, tmp );<br />  _Ptr[_Len+1]=0; // </span><span>讄引用计数</span><span>   <br />}<br />//</span><span>拯构造(׃n内存Q?/span><span><br />  string::string(const string& str)<br />  {<br />      if (*this != str){<br />        this->_Ptr = str.c_str();   //</span><span>׃n内存</span><span><br />        this->_Len = str.szie();<br />        this->_Ptr[_Len+1] ++; //</span><span>引用计数加一</span><span><br />      }<br />}<br />//</span><span>写时才拷?/span><span>Copy-On-Write<br />char& string::operator[](unsigned int idx)<br />{<br />  if (idx > _Len || _Ptr == 0 ) <br />  {<br />      static char nullchar = 0;<br />      return nullchar;<br />  }<br />  _Ptr[_Len+1]--;   //</span><span>引用计数减一</span><span><br />  char* tmp = new char[_Len+1+1];<br />  strncpy( tmp, _Ptr, _Len+1);<br />  _Ptr = tmp;<br />  _Ptr[_Len+1]=0; // </span><span>讄新的׃n内存的引用计?/span><span><br />  <br />  return _Ptr[idx];<br />}       <br /></span><span>      哈哈Q整个技术细节完全Q出水面?/span><span><br /></span><span>      不过Q这?/span><span>STL</span><span>?/span><span>basic_string</span><span>的实现细节还有一点点差别Q在你打开</span><span>STL</span><span>的源码时Q你会发现其取引用计数是通过q样的访问:</span><span>_Ptr[-1]</span><span>Q标准库中,把这个引用计数的内存分配在了前面Q我l出来的代码是把引用计数分配以了后面Q这很不好)Q分配在前的好处是当</span><span>string</span><span>的长度扩展时Q只需要在后面扩展其内存,而不需要移动引用计数的内存存放位置Q这又节省了一Ҏ(gu)间?/span><span><br />      STL</span><span>中的</span><span>string</span><span>的内存结构就像我前面ȝ那个图一P</span><span>_Ptr</span><span>指着是数据区Q?/span><span>RefCnt</span><span>则在</span><span>_Ptr-1 </span><span>或是</span><span> _Ptr[-1]</span><span>处?br /></span><span><br />2.4</span><span>?/span><span>臭虫</span><span>Bug<br /></span><span>      是谁说的</span><span>“</span><span>有太阳的地方׃有黑?/span><span>”</span><span>Q或许我们中的许多h都很q信标准的东西,认ؓ其是久经考验Q不可能出错的。呵呵,千万不要有这U迷信,因ؓM设计再好Q编码再好的代码在某一特定的情况下都会?/span><span>Bug</span><span>Q?/span><span>STL</span><span>同样如此Q?/span><span>string</span><span>cȝq个׃n内存</span><span>/</span><span>写时才拷贝技术也不例外,而且q个</span><span>Bug</span><span>或许q会让你的整个程?/span><span>crash</span><span>掉!</span><span>不信Q!那么让我们来看一个测试案例:</span><span><br /></span><span>      假设有一个动态链接库Q叫</span><span>myNet.dll</span><span>?/span><span>myNet.so</span><span>Q中有这样一个函数返回的?/span><span>string</span><span>c:</span><span><br />string GetIPAddress(string hostname)<br />{<br />  static string ip;<br />  ……<br />  ……<br />  return ip;<br />}<br />      <br /></span><span>而你的主E序中动态地载入q个动态链接库Qƈ调用其中的这个函敎ͼ</span><span><br />main()<br />{<br />//</span><span>载入动态链接库中的函数</span><span><br />hDll = LoadLibraray(…..);<br />pFun = GetModule(hDll, “GetIPAddress”);<br />//</span><span>调用动态链接库中的函数</span><span><br />string ip = (*pFun)(“host1”);<br />……<br />……<br />//</span><span>释放动态链接库</span><span><br />FreeLibrary(hDll);<br />……<br />cout << ip << endl;<br />}<br />      <br /></span><span>      让我们来看看q段代码Q程序以动态方式蝲入动态链接库中的函数Q然后以函数指针的方式调用动态链接库中的函数Qƈ把返回值放在一?/span><span>string</span><span>cMQ然后释放了q个动态链接库。释攑֐Q输?/span><span>ip</span><span>的内宏V?/span><span><br /></span><span>      Ҏ(gu)函数的定义,我们知道函数?/span><span>“</span><span>D?/span><span>”</span><span>的,所以,函数q回Ӟ一定会调用拯构造函敎ͼ又根?/span><span>string</span><span>cȝ内存׃n机制Q在ȝ序中变量</span><span>ip</span><span>是和函数内部的那个静?/span><span>string</span><span>变量׃n内存Q这块内存区是在动态链接库的地址I间的)。而我们假讑֜整个ȝ序中都没有对</span><span>ip</span><span>的D行修改过。那么在当主E序释放了动态链接库后,那个׃n的内存区也随之释放。所以,以后?/span><span>ip</span><span>的访问,必然做造成内存地址讉K非法Q造成E序</span><span>crash</span><span>。即使你在以后没有用到</span><span>ip</span><span>q个变量Q那么在ȝ序退出时也会发生内存讉K异常Q因为程序退出时Q?/span><span>ip</span><span>会析构,在析构时׃发生内存讉K异常?/span><span><br /></span><span>      内存讉K异常Q意味着两g事:<br /></span><span>1</span><span>Q无Z的程序再漂亮Q都会因个错误变得暗淡无光,你的声誉也会因ؓq个错误受到损失?br /></span><span>2</span><span>Q未来的一D|_你会被这个系l错误所煎熬Q在</span><span>C++</span><span>世界中,扑ֈq排除这U内存错误ƈ不是一件容易的事情Q?br />      q是</span><span>C/C++</span><span>E序员永q的心头之痛Q千里之堤,溃于蚁穴。而如果你不清?/span><span>string</span><span>cȝq种特征Q在成千上万行代码中找这样一个内存异常,直就是一场噩梦?/span><span><br /></span><span>备注Q要Ҏ(gu)上述?/span><span>Bug</span><span>Q有很多U方法,q里提供一U仅供参考:</span><span><br />string ip = (*pFun)(“host1”).cstr();<br /><br />3</span><span>?/span><span>后记</span><span><br /></span><span>      文章到这里也应该l束了,q篇文章的主要有以下几个目的Q?/span><span><br />1</span><span>Q?/span> <span>向大家介l一下写时才拯</span><span>/</span><span>内存׃nq种技术?/span><span><br />2</span><span>Q?/span> <span>?/span><span>STL</span><span>中的</span><span>string</span><span>cMؓ例,向大家介l了一U设计模式?/span><span><br />3</span><span>Q?/span> <span>?/span><span>C++</span><span>世界中,无论你的设计怎么_yQ代码怎么E_Q都难以照顾到所有的情况。智能指针更是一个典型的例子Q无Z怎么设计Q都会有非常严重?/span><span>BUG</span><span>?/span><span><br />4</span><span>Q?/span><span> C++</span><span>是一把双刃剑Q只有了解了原理Q你才能更好的?/span><span>C++</span><span>。否则,必将引火烧n。如果你在设计和使用cd时有一U?/span><span>“</span><span>?/span><span>C++</span><span>像玩火Q必d万小?/span><span>”</span><span>的感觉,那么你就入门了,{你能把q股</span><span>“</span><span>?/span><span>”</span><span>控制的得心应手时Q那才是学成了?/span><span><br /><br /></span></p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65255.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-27 22:56 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65255.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Singleton模式QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65252.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Mon, 27 Oct 2008 14:51:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65252.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65252.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65252.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65252.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65252.html</trackback:ping><description><![CDATA[class Singleton<br />{<br /> <p><span>public:</span></p> <p><span><span>    </span>static Singleton* Instance();</span></p> <p><span>protected:</span></p> <p><span><span>    </span>Singleton();</span></p> <p><span>private:</span></p> <p><span><span>    </span>static Singleton* _instance;</span></p> <p><span>};<span>      </span></span></p> <p><span>相应的实?/span><span> cpp </span><span>文g是:</span></p> <p><span>Singleton* Singleton::_instance;</span></p> <p><span>Singleton* Singleton::Instance()<br />{</span></p> <p><span><span>    </span>if( _instance == 0){</span></p> <p><span><span>        </span>_instance = new Singleton;</span></p> <p><span><span>    </span>};</span></p> <p><span><span>    </span>return _instance;</span></p> <p><span>}<span>      </span></span></p> <p><span><span>    </span></span><span>构造函数设计成</span><span> protected </span><span>的目的是防止?/span><span> class </span><span>外面</span><span> new </span><span>Q有人可能会设计?/span><span> private </span><span>Q假如考虑到有可能会l这个类的话Q还是将构造函数设计成</span><span> protected </span><span>比较好,q需要加一?/span><span> virtual </span><span>析构函数。ؓ了防止别人复?/span><span> Singleton </span><span>对象Q?/span></p> <p><span>Singleton* pSingleton = Singleton::Instance();</span></p> <p><span>Singleton s1 = *pSingleton;</span></p> <p><span>Singleton s2 = *pSingleton; </span></p> <p><span>需要将拯构?/span><span>(copy constrUCtor)</span><span>函数变成</span><span> private</span><span>?/span></p> <p><span><span>    </span></span><span>但是q里存在的问题是Q什么时?/span><span style="color: #ffff00;">删除</span><span style="color: #ffff00;"> Singleton </span><span style="color: #ffff00;">对象</span><span>Q按?/span><span> C++ </span><span>的一个基本原则,对象在哪里创建就在哪里销毁,q里q应该放一?/span><span> destroy </span><span>Ҏ(gu)来删?/span><span> Singleton </span><span>对象。假如忘了删除就比较ȝ?/span><span>Instance </span><span>函数q存?/span><span style="color: #ffff00;">多线E同时访问的加锁问题</span><span>。假如把</span><span> Instance </span><span>函数开始和l尾放上加锁和解锁,整个函数性能会下降很多。这不是一个好的设计?/span></p> <p><span><span>    </span></span><span>有一个小的改动Q可以避免忘了删?/span><span> Singleton </span><span>对象带来内存泄露的问题。那是?/span><span> </span><span style="color: #ffff00;">std:auto_ptr </span><span>来包?/span><span> Singleton </span><span>对象</span><span>,</span><span>定义一个类静?/span><span>auto_ptr成员</span><span>对象Q在析构静态的</span><span>auto_ptr </span><span>变量的时候时候自动删?/span><span> Singleton </span><span>对象。ؓ了不让用?/span><span> delete Singleton </span><span>对象Q需要将析构函数?/span><span> public </span><span>变成</span><span> protected</span><span>。以下是头文?/span><span> SingletonAutoPtr.h </span><span>Q?/span></p> <p><span>#include <memory></span></p> <p><span>using namespace std;</span></p> <p><span>class CSingletonAutoPtr </span></p> <p><span>{</span></p> <p><span>private:</span></p> <p><span><span>    </span>static auto_ptr<CSingletonAutoPtr> m_auto_ptr; </span></p> <p><span><span>    </span>static CSingletonAutoPtr* m_instance;</span></p> <p><span>protected:</span></p> <p><span><span>    </span>CSingletonAutoPtr();</span></p> <p><span><span>    </span>CSingletonAutoPtr(const CSingletonAutoPtr&);</span></p> <p><span><span>    </span>virtual ~CSingletonAutoPtr(); </span></p> <p><span><span>    </span>//allow auto_ptr to delete, using protected ~CSingletonAutoPtr()</span></p> <p><span><span>    </span>friend class auto_ptr<CSingletonAutoPtr>; </span></p> <p><span>public:</span></p> <p><span><span>    </span>static CSingletonAutoPtr* GetInstance();</span></p> <p><span><span>    </span>void Test();</span></p> <p><span>};<span>   </span></span></p> <p><span>对应?/span><span> SingletonAutoPtr.cpp </span><span>如下Q?/span></p> <p><span>#include "SingletonAutoPtr.h"</span></p> <p><span>#include <iostream><br /><br />//initial static member vars here </span></p> <p><span>CSingletonAutoPtr* CSingletonAutoPtr::m_instance = NULL;</span></p> <p><span>auto_ptr<CSingletonAutoPtr> CSingletonAutoPtr::m_auto_ptr;</span></p> <p> </p> <p><span>/////////////////////////////////////////</span></p> <p><span>// Construction/Destruction</span></p> <p><span>/////////////////////////////////////////</span></p> <p><br />//下列代码没有l过验证Q?/p> <p><span>CSingletonAutoPtr::CSingletonAutoPtr()</span></p> <p><span>{</span></p> <p><span><span>    </span>cout << "CSingletonAutoPtr::CSingletonAutoPtr()" << endl;</span></p> <p><span><span>    </span>//put single object into auto_ptr object </span></p> <p><span><span>    </span>m_auto_ptr = auto_ptr<CSingletonAutoPtr>(this);</span></p> <p><span>}</span></p> <p><span>CSingletonAutoPtr::~CSingletonAutoPtr()</span></p> <p><span>{</span></p> <p><span><span>    </span>cout << "CSingletonAutoPtr::~CSingletonAutoPtr()" << endl;</span></p> <p><span>}</span></p> <p><span>CSingletonAutoPtr* CSingletonAutoPtr::GetInstance()</span></p> <p><span>{</span></p> <p><span><span>    </span>//begin lock</span></p> <p><span><span>    </span>//....<span>    <br /></span>    if(m_instance == NULL)</span></p> <p><span><span>        </span>m_instance = new CSingletonAutoPtr();<span>    <br /></span>    //end lock</span></p> <p><span><span>    </span>//...<span>    <br /></span>    return m_instance; </span></p> <p><span>}</span></p> <p><span>void CSingletonAutoPtr::Test()</span></p> <p><span>{</span></p> <p><span><span>    </span>cout << "CSingletonAutoPtr::Test()" << endl;</span></p> <p><span>}<span>     </span></span></p> <p><span>调用Ҏ(gu)Q?/span></p> <p><span>CSingletonAutoPtr* pSingleton = CSingletonAutoPtr::GetInstance();</span></p> <p><span>pSingleton->Test(); </span></p> <p>      写一?C++ 中的 Singleton 需要这么费Ԍ大大Z我们的意料。有很多Z未用q?auto_ptrQ而且 std:auto_ptr 本nƈ不完,它是Z对象所有权机制的,相比之下QApache Log4cxx 中有一?auto_ptr, 是基于对象计数的Q更为好用。只是ؓ了用一个好?auto_ptr 而不得不?log4cxx , 对于很多目来说Q也不太好。当然了QANSI C++ ?STL ?std:auto_ptr 对于写上面的例子已经_用了?nbsp;    </p><p>      <span>另外一个思\是,?/span><span> GetInstance </span><span>函数设计?/span><span> static member </span><span>可能更好Q因Z般来_</span><span>Singleton </span><span>对象都不大,</span><span>static member </span><span>虽然必须一直占用内存,问题不大。这里的析构函数必须设成</span><span> public </span><span>了。以下是头文?/span><span> SingleStaticObj.h</span></p> <p><span>class CSingletonStaticObj </span></p> <p><span>{</span></p> <p><span>private:</span></p> <p><span><span>    </span>static CSingletonStaticObj m_instance;</span></p> <p><span>protected:</span></p> <p><span><span>    </span>CSingletonStaticObj();</span></p> <p><span> <span>  </span>CSingletonStaticObj(const CSingletonStaticObj&);</span></p> <p><span>public:</span></p> <p><span><span>    </span>virtual ~CSingletonStaticObj(); //must public</span></p> <p><span><span>    </span>static CSingletonStaticObj& GetInstance();</span></p> <p><span><span>    </span>void Test();</span></p> <p><span>};<span>     </span></span><span>对应?/span><span> SingleStaticObj.cpp </span><span>文g为:</span><span>#include "SingletonStaticObj.h"</span></p> <p><span>#include <string></span></p> <p><span>#include <iostream> </span></p> <p><span>using namespace std;</span></p> <p><span>CSingletonStaticObj CSingletonStaticObj::m_instance;CSingletonStaticObj::CSingletonStaticObj()</span></p> <p><span>{</span></p> <p><span><span>    </span>cout << "CSingletonStaticObj::CSingletonStaticObj()" << endl;</span></p> <p><span>}</span></p> <p><span>CSingletonStaticObj::~CSingletonStaticObj()</span></p> <p><span>{</span></p> <p><span> <span>   </span>cout << "CSingletonStaticObj::~CSingletonStaticObj()" << endl;</span></p> <p><span>}</span></p> <p><span>CSingletonStaticObj& CSingletonStaticObj::GetInstance()</span></p> <p><span>{</span></p> <p><span><span>    </span>return m_instance;</span></p> <p><span>}</span></p> <p><span>void CSingletonStaticObj::Test()</span></p> <p><span>{</span></p> <p><span><span>    </span>cout << "CSingletonStaticObj::Test()" << endl;</span></p> <p><span>}</span></p> <p><span><span>     </span></span><span>调用Ҏ(gu)Q?/span></p> <p><span>CSingletonStaticObj& singleton = CSingletonAutoPtr::GetInstance();</span></p> <p><span>singleton.Test();<span>     </span></span></p> <p><span>从代码量来说Q似乎?/span><span> static member ref </span><span>更ؓ单。我更偏向于用这U方法?/span></p> <p><span><span>    </span></span><span>但是Qƈ不是所有情况下面都适合?/span><span> static member singleton</span><span>。比如说Q?/span><span>GetInstance </span><span>需要动态决定返回不同的</span><span> instance </span><span>的时候,׃能用。D例来_</span><span>FileSystem::GetInstance, </span><span>?/span><span> windows </span><span>下面q行可能需要返?/span><span> new WinFileSystem, Linux/Unix </span><span>下面q行可能需要返?/span><span> new LinuxFileSystem</span><span>Q这个时候还是需要用上面?/span><span> auto_ptr </span><span>包含</span><span> singleton </span><span>指针的方法?/span></p><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65252.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-27 22:51 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65252.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>iterator中的?+和后++QC++Q?/title><link>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65239.html</link><dc:creator>zml_cnnk</dc:creator><author>zml_cnnk</author><pubDate>Mon, 27 Oct 2008 13:22:00 GMT</pubDate><guid>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65239.html</guid><wfw:comment>http://www.shnenglu.com/zmllegtui/comments/65239.html</wfw:comment><comments>http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zmllegtui/comments/commentRss/65239.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zmllegtui/services/trackbacks/65239.html</trackback:ping><description><![CDATA[     摘要: for(iterator it = begin(); it != end(); ++it) <br> 或?<br>for(iterator it = begin(); it != end(); it++) <br> 区别是什么呢Q? <br>…?<br> <br>  <a href='http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65239.html'>阅读全文</a><img src ="http://www.shnenglu.com/zmllegtui/aggbug/65239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zmllegtui/" target="_blank">zml_cnnk</a> 2008-10-27 21:22 <a href="http://www.shnenglu.com/zmllegtui/archive/2008/10/27/65239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.u1536.cn" target="_blank">޾Ʒһþþ </a>| <a href="http://www.05958.cn" target="_blank">ɫۺϾþþþ</a>| <a href="http://www.vrfx.cn" target="_blank">޾ƷþëƬ</a>| <a href="http://www.fqvb.cn" target="_blank">aaaƷþþùƬ</a>| <a href="http://www.cxdsj.net.cn" target="_blank">һɫþ88ۺպƷ </a>| <a href="http://www.y3d9.cn" target="_blank">Ʒݾþþþø99</a>| <a href="http://www.yousms.cn" target="_blank">þþþþþþƷɫ</a>| <a href="http://www.pluv.cn" target="_blank">99þþƷѿ</a>| <a href="http://www.tmsystem888.cn" target="_blank">޾ƷþþþĻ69</a>| <a href="http://www.xhqb2000.com.cn" target="_blank">һþöۺ</a>| <a href="http://www.jcfw-1.cn" target="_blank">þ99ȺݺɫƷһ</a>| <a href="http://www.macroshot.cn" target="_blank">ۺŮþþ30p</a>| <a href="http://www.7788797.cn" target="_blank">þӰۺ</a>| <a href="http://www.xiaoruhua.cn" target="_blank">91Ըߺþþþ</a>| <a href="http://www.gdciecco.cn" target="_blank">99þ99ֻѵľƷ</a>| <a href="http://www.engil.cn" target="_blank">vaþþþ</a>| <a href="http://www.ttzhan.cn" target="_blank">þþ뾫Ʒҹ</a>| <a href="http://www.kangle.net.cn" target="_blank">Ůþþþþjþ</a>| <a href="http://www.sdhaomai.cn" target="_blank">Ʒþ</a>| <a href="http://www.ciao-surveys.cn" target="_blank">þۺϸϾþúݺݺ97ɫ</a>| <a href="http://www.ithaiyang.com.cn" target="_blank">һþþ</a>| <a href="http://www.qsstudio.cn" target="_blank">ŷ޹׾þþþþþ </a>| <a href="http://www.udhv.cn" target="_blank">Ʒþһ</a>| <a href="http://www.linan521.cn" target="_blank">޺ݺۺϾþѿ</a>| <a href="http://www.z1359.cn" target="_blank">Ʒպþ</a>| <a href="http://www.aliyundjq.cn" target="_blank">þĻƷһ </a>| <a href="http://www.xfqbaby.cn" target="_blank">һþƵ</a>| <a href="http://www.ebianlian.cn" target="_blank">þۺϺݺۺϾþ97ɫ</a>| <a href="http://www.baizen.cn" target="_blank">þ99Ʒþþþþ9 </a>| <a href="http://www.sijishi.cn" target="_blank">þþ</a>| <a href="http://www.dyhao.com.cn" target="_blank">91þþƷӰ</a>| <a href="http://www.ksxhsd.cn" target="_blank">99þþù</a>| <a href="http://www.caikuaipeixun.com.cn" target="_blank">þùƷ</a>| <a href="http://www.misuca.cn" target="_blank">ҹƷƬþӰ</a>| <a href="http://www.chcrw.cn" target="_blank">97Ʒ˾þô߽app</a>| <a href="http://www.beo.net.cn" target="_blank">þþƷƷëƬ</a>| <a href="http://www.mxcqsf.cn" target="_blank">߳߳þþ</a>| <a href="http://www.mofeigzs.cn" target="_blank">2021þùԲľƷ</a>| <a href="http://www.e8ux.cn" target="_blank">þþƷ</a>| <a href="http://www.bluecc.com.cn" target="_blank">ݹƷþ</a>| <a href="http://www.jzqyc.com.cn" target="_blank">Ʒþþþþ99</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>