CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
英特尔®游戏设计大赛100美元现金周周送 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

10分清茶,相邀讨论2个c++底层问题,非高人婉绝

楼主fretre()2003-02-03 16:42:54 在 C/C++ / C++ 语言 提问

1   对象实现的主要原理,我并不陌生。  
      让我困惑的是为什么非得在running   time创建对象?在我看来,创建对象,同其它  
  c/c++全局数据结构一样,完全可以让编译器在compling   time创建,或者至少可以提供  
  一个选择策略,让用户自己选者是动态还是静态创建,这样一来,所谓seriesing完全多余,编译器自己就把事儿给干了--在c环境中,谁需要seriesing?(当然,c中动态创建的玩意也不宜直接写文件保存,但动态创建主要用于一些临时目的,完成主要功能的数据结构大多是compling   time创建。)  
      再次困惑:为什么非得在running   time创建对象?  
   
  2   构造函数用来初始话对象的成员,(默认构造函数什么也不做,对象的成员状态未定  
  ),这是大家都了然的。  
      可我们看到的构造函数仅仅用来初始话对象的成员,至少表面上看来如此,那为什么  
  不称构造函数为初始化函数?这样岂不更贴切?它的构造功能--准确的说构造对象的功  
  能体现在哪里?构造对象是要经过底层一系列的动作才能完成的,可我始终看不出构造函数干了什么。  
  问题点数:0、回复次数:134Top

1 楼efanl(传说中的一凡……)回复于 2003-02-03 17:17:58 得分 0

第一个问题不敢冒然回答,第二个问题有点看法:  
          1.默认构造函数并不是什么也不做,而是在没有提供对象信息的情况下,构造对象。因此成员状态并非未定义,而是采用“默认值”。  
          你虽然看不出构造函数干了些什么,但其实编译器为你做了许多。比如说虚函数表的建立等等。  
          2.若名为“初始化”,就不像是面向对象的词了,感觉就是把数据和数据的含义分开来,仅仅是给成员变量赋初值。  
          相反,采用“构造”这个名字,才真真正正令人觉得你是在生成一个“对象”,而不是单纯地给一些变量赋值……  
          不知道老外给它取名为“Constructor”是不是这个意思^_^Top

2 楼brucegong(飞行猪)回复于 2003-02-03 18:02:56 得分 0

 
   
   
   
  第一个问题:  
   
  你研究得很深,但是偏离了方向——因为你研究的是C++的编译过程而不是C++的OO特性。或者说你的着眼点太小,研究的是很小的应用。如果你看了corba,了解了OO系统在大的机群里面的应用的时候,就会觉得动态创建是绝对必要的。至于为什么没有你说的那种功能——那个应该是编译器的特性,不能作为C++的特性。那么做实际上是回到了绝对定位地址的汇编时代——完全没有必要啊。  
   
  第二个问题:  
   
  和第一个问题的原因相似。我们通常可以在构造函数中干很多事情,但是构造函数的本意仅仅是创建和分配资源。试想一下这样的应用:你要创建100个对象,他们之间有某种依赖关系,你必须按照某种顺序分配资源之后才能确定对他们的初始化策略,而初始化的时候还要遵守一定的顺序……这种情况在你编写一个大型的支撑系统的时候很容易遇到。  
   
  老外的定义是很严谨的。  
   
   
   
   
   
  Top

3 楼fretre()回复于 2003-02-03 18:43:45 得分 0

to   efanl:不必客气,大家共同探讨:)  
   
      我说的也是这个意思,“构造对象,编译器其实编译器为你做了许多。比如说虚函数表的建立等等。”  
      我只是想知道,构造函数是如何参与其中的,因为从任何一个构造函数仅从其表面定义来看,都没有任何构造对象的代码,默认构造函数的定义更是一个空函数,从这个角度来看,它就是什么也不做。  
      当然,实际上并非如此,就像你所说“默认构造函数并不是什么也不做,而是在没有提供对象信息的情况下,构造对象”  
   
      我相信构造函数的确担当了构造对象的主要角色,取名Constructor绝非随意。  
   
      一方面,各种"深度探索"的资料展示了对象构造的细节,可就是没有明确涉及Constructor所起的作用,而谈到Constructor的时候,展示的却是它初始化对象成员的功能,所以我想了解一些Constructor做“本职工作”的情况。  
        我想明确了解的是:构造对象的代码是否包含在Constructor里面?如果是的话,一个用户显式定义的Constructor就包含了2部分代码,一是构造代码,二是用户定义代码,着2部分代码如何衔接?  
         
   
   
   
  Top

4 楼xghost(菜鸟)回复于 2003-02-03 20:19:56 得分 0

upTop

5 楼fretre()回复于 2003-02-03 20:28:33 得分 0

to   brucegong:  
    我的问题的确较深,但我不认为是“偏离了方向”。也不认为是“研究的是很小的应用”  
      了解一些底层(编译器)实现对象的细节是任何一个想深入理解c++人都无法回避的。  
      你认为“如果你看了corba,了解了OO系统在大的机群里面的应用的时候,就会觉得动态创建是绝对必要的。”----这是从一个角度说明了动态创建的重要性--很好!   虽然我并不认为非得“看了corba”才能体会这一点  
   
      c++应该本身就能说明为什么要动态创建对象!可这正是我还不够了解的。  
   
      你的回复中有一点认为这是为了避免“回到了绝对定位地址的汇编时代——完全没有必要啊。”  
      关于这一点,我可以说明的是,无论是unix还是windows环境,动态链接技术已经很好地解决了寻址问题,不管是静态地址还是动态地址,我以为动态实现对象的主要目的不仅仅出于寻址方便。  
  Top

6 楼earthharp(我老子是土匪)回复于 2003-02-03 21:06:41 得分 0

object   ==   class   ?  
   
  C++对象提供的是值语意,对于如同C   struct初始化的语句,必然也要能构造。所以构造函数在很多情况下并没有实际作用。  
   
  Top

7 楼brucegong(飞行猪)回复于 2003-02-03 22:58:03 得分 0

 
   
   
   
   
   
  fretre()   (   )  
   
  你的问题我曾经也问过别人。那个时候刚刚学习了C++的语法,跟踪了几个程序。加上本人的汇编功底还可以,当时跟踪到了源代码级别。于是有一天我在一个老头子面前很是不屑地认为C++有点名不副实,然后拿出我跟踪到汇编地经验和他“探讨”。一向和颜悦色的老头子拿出一本书说“看完它之前不要和我谈C++”。当然,看完之后我还是没有和他谈,因为我不知道我还会有什么笑话闹。  
   
  学习C++乃至于OO,没有面向过程的那点功底是绝对不行的,然而用面向过程的东西来分析OO却是不幸的。虽然他们到了二进制的级别上已经没有多少差别(其实本来就没有差别)。  
   
  如果不讨论应用层的东西,那讨论OO或者C++干什么?  
   
  OO里面的深层次问题不是编译或者链接,而是OO系统的合理性、可扩充性以及安全性等等……  
   
  听说《thinking   in   C++》不错,不过我没有看过。我看的是《设计模式》。看完之后翻然醒悟,后悔当初对创立C++和OO的各位前辈的无礼言论……  
   
  看完上述的两本书中的任何一本,你即使在编译和链接上还有疑问,也不是在上述的两个方面了。  
   
   
   
   
   
   
   
  Top

8 楼Caoyu015(酷鱼一代)回复于 2003-02-04 05:07:54 得分 0

楼上做过的事也是我以前做过的,所以又同感。Top

9 楼liuns(^_^)回复于 2003-02-04 10:16:05 得分 0

1.   run   time   中创建对象有利于方便的建立动态消息循环和对象的连接建立.如果仅仅是在全局创建的话估计代码的质量不是很高(东一个西一个的).  
  2.   构造函数本身就是初始化函数,但他必须得存在,因为编译系统需要他.就象你到某地办事必须得走路去,但是你本身不修路,路是别人修好的.构造函数就象这个路一样,你用他的时候在你的心中他才存在.你可以很方便的通过这个路到达你想到的任何地方.你如果不出门这个路对于你来说没没有用.但对于别人还是有用的(这个就象默认构造函数)Top

10 楼libi(风自吟)回复于 2003-02-04 12:54:47 得分 0

非常赞同brucegong(飞行猪)的说法。  
  run   time   中创建对象是OO的思想,C++语言本身并不能体现这点。比方说庖丁解牛的刀,并不是刀可以解牛,解牛的是人,刀只是工具,只是这把刀的形状、尺寸、锋利程度比较适合于解牛,C++仅是刀而已。  
  至于如何理解run   time   中创建对象的必要性,每个人都有自己的体会,你能提出这样的问题,那也是达到一定的层次了,建议你看看《设计模式》这本书,或许能有所获。我的编码经验值不足1k(代码行),自己对此的体会很模糊,所以难以向你说明它的必要性,你不妨看些书,自己体会。总之,run   time   中创建对象远比compling   time中创建灵活,而且有些对象的参数要到run   time   才能确定。  
  至于构造与初始化,正如brucegong(飞行猪)所说,只是老外的严格定义罢了。比如一个缓冲区对象,为它分配多大的空间,那是构造函数的事,缓冲区内的初始值则是初始化的事。这两个概念,我想,你是能够区分的。能够从概念上区分则足以,并不是说非要在实现代码上区分得明明白白,如果系统不需要,你完全可以把这两部分放在一个构造函数里做,心里明白此点即可。但有些对象是必须分开的,例如可以reset的对象。  
  学习软件,关键是学习它的思想,至于具体怎么实现可以根据具体的需求而定,切不可拘泥于形式,要灵活。如果你看《设计模式》,切记这一点,不要为模式的具体形式所困惑,关键要看明白它是如何实现解耦的。  
  Top

11 楼superzjx2000(承桴浮于海)回复于 2003-02-04 15:52:31 得分 0

1     oo的问题域是软件工程  
  2     oo的一切问题的理解应着眼于seTop

12 楼xbin999(xbin)回复于 2003-02-04 16:21:28 得分 0

upTop

13 楼fretre()回复于 2003-02-05 20:17:38 得分 0

有趣!  
   
  提2个技术问题,本来是想听听高见,没想到听见的却是brucegong(飞行猪)   说的一个故事,故事的意思再明白不过了,不就是说我现在的水平只相当于你那时候的水平,甚至还不如你,以至于我提出这2个技术问题都让你觉得是“闹笑话”  
   
  不懂就问!即使在专家面前,我也没觉得有什么好笑的,说不定能得到专家指点,岂不是件好事?  
   
  倒是专家的回答令人费解,跟技术沾边的话没几句,却煞有其事地抬出一“老者”,仿佛你从那位世外高人那里得到了点拨,不回顾一下那段奇遇就对不住你的恩师,更不足以彰显你的水平。  
   
  羡慕你得到高人指点啊!  
     
  顺便打听一下,那什么“慈祥的老者”给阁下介绍的那什么宝典,你看懂了吗,应该功力大长了吧?能不能赐教在下一二?   愿意多说就多说几句,要是觉得不屑多说,泛泛而谈也行,是骡子是马,牵出来遛遛,总比故弄玄虚要好,我是洗儿恭听啊!  
   
  要是你没看懂那什么宝典,也不要紧嘛,不妨介绍给大家看看,你看不懂不等于别人也看不懂,大家看懂之后还可以帮你啊,不要怕笑话,就怕不虚心求进又自我感觉良好,那才会永远被人笑话。  
   
  故弄玄虚也没什么,只是觉得特没劲,一百个零只不过是零。  
  Top

14 楼huzhangyou(信仰(http://www.libing.net.cn))回复于 2003-02-05 20:55:16 得分 0

不知所云Top

15 楼brucegong(飞行猪)回复于 2003-02-05 22:06:25 得分 0

 
   
   
   
   
  我已经说了很多次了,那本书就是《设计模式》。  
   
   
  我说那位老者完全是我亲身经历的事实。我很惭愧当年自我感觉良好的时候目中无人,很感激他没有因为一个晚辈的自负、无礼和无知而不告诉我真理的方向……  
   
  现在才知道你来这里并不是为了真正讨论问题,而是为了炫耀你对C++了解得多深了。我已经回答了你目前的问题,作为一个比你早一点走上编程这条路的人,我已经没有什么对不住你这个后辈的了。上面说的那么多你可以当我没有说过,那本书你也可以当作是一部垃圾著作……以你现在的水平,要找一个差不多的工作其实也是可以的了。国内实际上真正用到那么完整的OO的公司应该还没有。  
   
  ——所以你可以继续自我感觉良好去。  
   
  我懒得说你了,请不要接着和我讨论这个问题(要骂人随你便)。更不要给我留言。  
   
   
   
   
   
   
  Top

16 楼PPower(月亮光光,照地堂)回复于 2003-02-05 22:14:04 得分 0

我不明白:水平差,來學習,希望告訴我。  
  1、我們寫代碼時確實可以選擇:  
  對象是动态还是静态创建。沒有強迫要动态创建啊。  
  2、seriesing的中文是什麼?我一頭霧水。  
   
  我說不出什麼道理來,把我的看法寫一寫(不對就罵,不要扔石頭呵,閃)  
  對象:它並不可以簡單地看成是一塊數據區(內存),加是操作這些數據的方法。如果是那樣看,倒象是寫數據庫程序了。這是一個抽象的概念,作個比喻,我要構造一個對象(實例),但我現在不知是什麼對象?要運行期才知道(要生孩子了,但不知是男是女是生是死,一胎還是多胎,要生下來檢查後才知道是什麼),難道要等到那時候你才去寫程序,重新編譯運行嗎?(静态创建如何做到?)。OO編程可以解決這類問題,學習C++,首先要搞清楚什麼是對象,這個抽象的概念。  
   
  我始终看不出构造函数干了什么?  
  我也不明白。构造函数:就是要生成這個對象,(默认构造函数什么也不做?如果是有繼承的情況呢),构造对象的功能体现在哪里?就在構造函數中。一個對象它的大小在多繼承的情況下會變得很複雜,我不清楚。如果叫初始化函數,那也該先有對象才能初始化吧,C++中沒有一個初始化函數,我想因為那初始化代碼可以寫在構造函數中,實無必要再生枝節。VCL對象是有個OnCreate函數,但C++沒有。  
   
   
  Top

17 楼szlbyou(无里头)回复于 2003-02-05 22:42:25 得分 0

呵呵,我完全支持brucegong(飞行猪)!!!Top

18 楼PPower(月亮光光,照地堂)回复于 2003-02-05 22:52:17 得分 0

從面向過程編程到----面向對象編程     這個過程是編程思想的轉變,與個人的考試水平,編程能力無關。我是比較蠢的一種,花了三年時間才轉變過來,但還是摸黑走路,未能登堂入室。  
   
  如果用青蛙的眼光去看天空的小鳥,是很難理解為什麼小鳥能飛起來的。小鳥也無法明白為什麼整個冬天那青蛙不吃不喝竟然還能活下來。讓我們用人類的頭腦去學習去分析:原來青蛙與小鳥有共同的地方,也有不同的地方!青蛙可看作一個對象,小鳥也可看成一個對象,它們共同的地方(動物)還可以看成一個對象,說准確點是虛擬的對象,(小鳥)能飛,(青蛙)冬眠,這些特性也可以分成一個個對象(類)。妙哉!這個對象是無所不包的,對象虛對象就象是陰陽二氣(有與無),是相互轉換變化無窮。如果把實例稱為“有”(陽),虛類稱為“無”(陰),再想想,無中生有,有中含無,這些古代的哲學也不無道理啊。  
   
  如果認為面向對象不很複雜的話,多看看書吧。  
  如果用面向過程的觀點去看待面向過程的程序,多思考思考吧。  
  如果不願意使用面向對象來編程的話,學習C++真是多余的,C就做得很好了。Top

19 楼whoke(hy)回复于 2003-02-07 11:00:28 得分 0

PPower(引線穿針)   说得好!  
  construct   和initialize   不一样Top

20 楼efanl(传说中的一凡……)回复于 2003-02-07 11:21:06 得分 0

探讨问题嘛,何必说得这么绝断呢……  
          飞行猪的故事好神奇呀,希望你可以像那位老者一样,不要“因为一个晚辈的自负、无礼和无知而不告诉我真理的方向……”。  
   
          fretre我现在有点糊涂,你是觉得构造函数做的事情太少,没有体现“构造”是吗?但不同的类对其对象的构造有不同要求,复杂的对象的构造自然要复杂得多。但简单的类有时甚至不需要什么动作,比如只有一个int型成员的类,只要分配空间就够了。如果这样一个对象都要动手脚的话,恐怕面向对象编程就没人敢用了。  
          自己写的代码并不是构造函数的全过程,有些是编译器加上去的。但有时候构造函数确实什么都不做,甚至在那种时候,编译器根本就不会产生构造函数!  
          看过《深入探索C++对象模型》一书吗?里面有详细讨论。Top

21 楼glassshark(★★★★★★)回复于 2003-02-07 11:35:07 得分 0

如果知道微积分是谁发明的,是为什么发明的,你就明白了OO的作用,OO不是理论不是思想,它真正的用途是“使用”,如果“简单的类有时甚至不需要什么动作,比如只有一个int型成员的类,只要分配空间就够了。如果这样一个对象都要动手脚的话,恐怕面向对象编程就没人敢用了。”我实在看不出这样的说法有什么争论的意义。如果它真象你说的那样简单,为什么还要用类呢?如果需要用类,那当然就是OO了,用还是不用都取决于你,有需要就用,我很烦整天争论理论思想的人。  
  中国是先搞理论再搞实践的人多,只搞理论的人更多。  
  国外是先搞实践再搞理论或者两者同时进行的人多,但正因为如果才成就了更实用更先进的理论。  
  理论是来用的,不是来争的,如果对你无用就是无用的理论。  
  如果你的思维方式是面向结构的,而不是面向对象,只要它够系统成熟,你完全可以编出很好的程序,甚至比面向对象还好。  
  不过你有没有考虑过,int是不是对象?它有没有属性集?  
  Top

22 楼huangsui(呆呆虫)回复于 2003-02-08 10:21:11 得分 0

那有编译时创建对象的?  
  有些对象又不是一定要创建。。。  
  你这样对大多数程序来说肯定是不行的。。  
  更何况很多对象的创建信息依赖于前面的运行的情况!!!Top

23 楼ALNG(?)回复于 2003-02-08 10:46:08 得分 0

1.   你是想象C一样的编译期准备好的已初始化对象和未初始化放在bss的对象吧?  
   
  考虑一下这样一个类:  
        struct   string{  
                  string(unsigned   size):size(size),buff(new   char[size]);  
                  ~string(){delete   []   buff;}  
                  //   other   stuff  
        private:  
                  unsigned   size;  
                  char   *   buff;  
        };  
   
  这个类的对象创建时需要在堆上分配内存。如果你声明一个  
  string   s(1000);  
  的全局对象,编译器永远不可能知道s.buff应该放置什么值。  
   
  所以在main运行前,一定要有个初始化全局对象。不知道我说的和你问的事不是一码事。Top

24 楼ALNG(?)回复于 2003-02-08 10:51:13 得分 0

2.   constructor和destructor   命名上有一种对称美。   如果最初的术语把他们命名成了initializer和cleaner,   我们也会欣然接受。  
   
  trait   class   在叫trait前,Myers称他为baggage   class,   如果标准委员会决定成为baggage的话,我们会介意吗?不会。  
   
  同样不知道我说的和你问的事不是一码事。  
   
   
  Top

25 楼ALNG(?)回复于 2003-02-08 10:53:10 得分 0

or.  
   
  你认为构造函数要做些什么才配得上称为构造函数?Top

26 楼alicejwh()回复于 2003-02-08 11:30:21 得分 0

一点儿看法,兄弟姐妹共同探讨:  
   
  第一个问题:创建对象的一个重要工作就是给对象分配内存空间,在编译阶段就确定下类对象的内存大小以及内存地址似乎不太容易,因为我们知道只有一个应用程序运行起来后才称为操作系统的一个进程,并且操作系统才为这个进程分配空间,而这些进程中各个变量所占的空间均在这个进程空间之内。  
   
  第二个问题:C++语言中构造函数的功能不只是简简单单的进行类的数据成员初始化的工作,它的重要工作是为类对象分配内存,其实,如果,在构造函数中,即使没有对类数据成员初始化的代码,系统在分配内存时也会根据数据成员的数据类型进行相应的初始化,因此,构造函数不能等同为初始化函数。Top

27 楼ALNG(?)回复于 2003-02-08 11:48:01 得分 0

alicejwh().  
   
  每个进程有独立的逻辑地址空间,一般进程并不关心其实际的物理地址,所以这实际上不是问题。Top

28 楼merlinran(天行者)回复于 2003-02-08 12:16:56 得分 0

第二个问题:  
  在C++中,对象的创建分成两个部分:allocation和initialization,前者又包括三种方式:static、automatic和dynamic,而后者只有一种方式,就是通过调用constructor。C++并不是一开始就把内存分配和初始化分开来考虑的,这可以在Bjarne的书《the   design   and   evolution   of   C++》中看到。所以,你也可以把构造函数叫做初始化函数,对实际意义并没有区别。C++的设计并不是为了研究目的,而是为了实用,所以区分这些名词意义不太。  
   
  初始化强调数据本身,而构造一词强调完整的对象。建立一个对象,让它处于某个完整的状态,即为构造。你可以说construct一座大楼,但可以说initialize一座大楼吗?  
   
  第一个问题:  
  serialization(可以译为串行化吗?)和动态创建不是同一个意思,但还是比较相关。  
  并不是所有东西都是编译时知道的。动态创建的一个简单例子,你的程序要对键盘输入的数排序,而数的数目是事先不知道的。你可以用一个足够大的数组,这样就无需动态创建,但你会这样做吗?  
  这就是串行化的一半:根据输入信息重组内存结构,另一半是把内存结构保存起来。数据库也是一种方式。  
   
  设计良好的动态创建可以让对象的使用者无需关心对象的位置、如何构建,这降低了程序各部分的耦合。而分布式对象则非动态创建不行。《设计模式》这本书确实可以解决楼主的很多疑问。我自己还是一个自学者,没有任何开发经验,但设计模式给了我很多东西。  
  一个良师可以让人少走很多弯路,如果得遇,实为大幸。希望大家不要为此争吵。  
   
  继续讨论。  
  Top

29 楼cwanter(亚玛逊河上的渔夫)回复于 2003-02-08 13:45:41 得分 0

学习Top

30 楼cwanter(亚玛逊河上的渔夫)回复于 2003-02-08 14:01:39 得分 0

在running   time创建对象是指什么?分配内存还是初始化?内存是在编译期分配的,初始化是在运行期。至于为什么要调用构造函数初始化对象,那是C++的语法问题了。《设计模式》这本书没看过,所以对这个问题不敢妄加论断。Top

31 楼fretre()回复于 2003-02-08 14:05:45 得分 0

谢谢ALNG和merlinran天行者的回复,非常切题,在下受益颇多,也谢谢各位!  
   
  下面我先简单谈谈我对ALNG举例的分析,希望大家再进一步指教!  
   
  1   计算对象大小:  
  unsigned   size;   4   byte  
  char   *   buff;       4   byte  
  为讨论方便,我忽略了可能有的bptr,vptr,padding大小  
  至于buff指向的内存大小不能算到对象里面。  
   
  2   第一部没有异议,进入第二步  
      这8byte就是string对象的实体了,就像国土对于国家这个概念一样重要。  
      这8byte本身由谁负责?静态实现当然由complier,动态只能靠constructor,但能从任何一个constructor看到开辟对象的代码吗?看不到,看的到的代码只是constructor作初始化赋值的代码,从看的到层面来说,constructor就像初始化函数。  
      当然,constructor不仅仅干这个,它首先要担负起本职工作--开辟对象,只不过这一部分对程序员透明,看不到。  
      到这里,我想明确一下我首帖第2点的意思,我完全认为constructor名副其实!  
  尽管就ALNG举例的string对象,我可以给出其constructor的一些底层实现代码以供大家指正,但我并不认为我对constructor   allocation有多少理解,我就是想在allocation实现方面向各位学习、交流。  
   
  3   关于动态实现和静态实现,ALNG和merlinran的帖子已经在很大程度上消除了我的困惑,感谢!我仍将在下一贴继续谈谈我个人的理解,以展开讨论,提高自己的见识。Top

32 楼ALNG(?)回复于 2003-02-08 14:59:17 得分 0

我的理解是这样的。  
   
  如果有一个上面的string类。假定sizeof(char   *)==sizeof(unsigned)==4bytes.  
   
  1.   对于全局对象:  
        string   s(1000);  
  s本身所占的8bytes是在编译期决定的[当然对象在内存中的实际布局对程序员不是透明的].   但是这8bytes在程序被OS装入内存而成为一个进程的那一瞬间,它的值是未定义的。C++不希望有未正确构造的对象引起不变,所以,在进入main之前,编译器产生的代码保证s会被正确构造,相当于调用了一个  
          new(&s)(1000);     //   placement   new  
   
  2.   对于静态对象情况和全局对象类似,但是初始化的时机可能不同,比如:  
        void   f(int   i){  
              static   string   s(100);  
            //   more   stuff  
        }  
      s   可能在f的第一次被调用时初始化。  
   
  3.   对于自动对象,其实际位置是运行时决定的,编译器产生一个sub   sp,8  
  的指令为其准备空间,并调用相应的constructor对其进行初始化。  
   
  当然,s.buff所指向的空间都是运行时分配的。  
  Top

33 楼ALNG(?)回复于 2003-02-08 15:07:40 得分 0

你说的是对的,不管怎样这8个byte是编译期决定的[只不过对自动对象而言,其位置相对于ebp是确定的,而ebp基本上就是进入函数时esp的状态].   constructor对于在那里construct这个string对象,确实没有任何发言权,就象建筑工人[constructor],   工地的选址不是他的权限和职责的范围。这个意义上,他的确就是initializer.   当然,如果需要进一步的外购材料,constructor有发言权。在这个例子里,buff所指向的空间,他虽然没有决定权,但至少他提出了申请,有知情权。Top

34 楼ALNG(?)回复于 2003-02-08 15:16:44 得分 0

如果你关心这些内容,stanley   lipman的inside   the   c++   object   model一定很对你的胃口。Top

35 楼xcopy(xcopy)回复于 2003-02-08 15:49:56 得分 0

我想说的是关于动态创建对象的问题,以我的经验来看,这样做主要是为了方便继承和多态。拿一个最常用到的例子:画板。   对于矩形,圆形,三角形,我们分别有三个类来绘制,他们都是从一个抽象基类继承而来,并且重载基类的纯虚函数draw().在具体绘图的时候,我们创建一个基类指针,并将它指向一个具体的基类。然后通过这个指针就可以进行绘制操作。在编译的时候不可能知道用户要进行什么操作,也就是不知道应该指向那个子类。只有在运行的时候才可以得到用户的请求,然后动态的创建绘图的对象。  
  这些概念在java里体现的更为清晰些,java里有interface和classfactory来实现。c++没有专门强调这一点,但是用的多了就出来了。Top

36 楼MarkDong()回复于 2003-02-08 15:53:55 得分 0

对于第一个问题,我想对于实现永久对象,可能没有什么比run-time构建对象更好的方法了。  
   
  对于第二个问题,我觉得应该看看《深度探索C++对象模型》,constructor实际做了很多的工作,也许你从代码上看不到,但不代表没做工作。Top

37 楼fretre()回复于 2003-02-08 16:51:13 得分 0

很高兴看到朋友们向我提到stanley   lipman的inside   the   c++   object   model,这使我相信你们回信的分量。  
  我曾经反复研读过这本书,在论坛上发帖子之前又将它回顾了一编,我以为在众高人面前讨论一些问题,具备这个底子是必须的。  
  恕我直言,inside   the   c++   object几乎设涉及了c++各个底层领域,但在揭示constructor方面,更多的是讲述initialization,   allocation用墨不多,也许是处于篇幅考虑。唯一让我特别感兴趣的几句话是在一个范例里面,而这个范例还主要是讲如何写高效率的initialization代码,估计各位已经知道我说的这个范例在那本书的第几部分了吧,例子我就不帖了,我希望各位能给我指出这本书里其他涉及allocation的文字,书就在手边,如能在线探讨研习心得,更是爽事!  
   
  to   ALNG:  
  你在回复中多次使用了汇编级代码,你在这个级别解剖过c++对象,堪称彻底!  
  有空我会在这个方面向你讨教,有些问题回避汇编码就说不太清。  
   
  另外,各位对动态创建对象的看法对我很有启迪,我会进一步就这个问题和大家交流。  
  Top

38 楼merlinran(天行者)回复于 2003-02-08 20:09:16 得分 0

我觉得大家对inside   the   c++   object   model这本书太高估了。它揭示的是底层实现的机制,但我并不觉得它有多高深,也不是独一无二。  
   
  我看这本书时,还没有看thinking   in   C++(这也只能算是本入门读物),对很多东西连概念都没有,但几天就看完了。实现是为了反映概念,它本身并没有什么奇怪的。  
   
  我觉得掌握OO思想相对而言更重要。像这次的问题,如果大家看了设计模式,可能就不会局限于内存分配这样的底层机制了。  
   
  我觉得《the   design   and   evolution   of   C++》是本好书。对C++的实现机制,如虚函数、虚基类,它有详细的解释,包括各种方案的抉择。更重要的是,看了它,你可以知道C++的发明者希望大家怎样使用C++,这其中也有作者自己不断接受新的OO概念的过程。  
   
  理论指导实践,这个理由可能可以说服大多数人。实现机制也是由设计思路所决定的。Top

39 楼earthharp(我老子是土匪)回复于 2003-02-08 20:57:51 得分 0

我比较同意merlinran(天行者)的观点。  
          hou   sir在书的评介里写道,这是一本定位在高阶的书。当然有其道理。  
  我看此书之时C++语法都没有学完(对C掌握的还可以),看起来的感觉就是妙不可言。不过现在我十分后悔,我不该过早的看这本书。  
          正是这本书让我完全沉迷于C++的语法语意,这些东西搞起来极快意。但是其实这是走了很大的弯路。我觉得根本就没有必要去钻研这些东西,因为C++语言体系庞大,在设计中甚至很难在几种模型中进行选择和综合运用。再加上古怪的语法和实现语意,就很容易让人走入语言的深渊。这样是很不好的,浪费大量时间,实际是歪门邪道。  
            对于什么虚函数的实现啊,template如何具现,对象模型啊,各种各样的细节,其实对自己功力的提高在某种程度上并不大。  
            当然,学习它们是有好处的。但是这些东西完全可以到以后再学习,那时候驾轻就熟,体会也更深刻。  
            真正最重要的东西,当然是思想。所以大家不要把过多的精力放在语言层面上,那样很不划算。这个论坛上的问题全部都是关于语言的细节问题,却很少涉及设计方面。而且,偶这几千分也基本都是靠回答这种问题得到的。这就表示大家都没有真正的学到C++,学到精髓。我甚至推荐每一个学习程序设计的人使用C#或者Java,然后再学习C++和C,那样效果可能会好很多。  
            希望每一个人都认真学习设计模式,学习软件构造,学习OOP与UML,这才是真正提高自己能力的最好途径。  
            只推荐一本书:   Design   Patterns   Explained.   不管你是初学还是高手,你都不能错过。Top

40 楼PPower(月亮光光,照地堂)回复于 2003-02-09 17:34:59 得分 0

設計模式,軟件復用,在實際開發團隊中應該如何運作,不知有沒有這方面的書,希望各位介紹。  
  OOSE(面向對象的軟件工程過程),對於個人來說容易貫徹一些,可對於一個開發團體來講,不知怎麼辦。Top

41 楼JoshuaLi()回复于 2003-02-25 16:13:57 得分 0

回复人:   glassshark(追赶蜗牛(50/57))   (   )   信誉:100     2003-2-7   11:35:08     得分:0    
     
     
       
  如果知道微积分是谁发明的,是为什么发明的,你就明白了OO的作用,OO不是理论不是思想,它真正的用途是“使用”,如果“简单的类有时甚至不需要什么动作,比如只有一个int型成员的类,只要分配空间就够了。如果这样一个对象都要动手脚的话,恐怕面向对象编程就没人敢用了。”我实在看不出这样的说法有什么争论的意义。如果它真象你说的那样简单,为什么还要用类呢?如果需要用类,那当然就是OO了,用还是不用都取决于你,有需要就用,我很烦整天争论理论思想的人。  
  中国是先搞理论再搞实践的人多,只搞理论的人更多。  
  国外是先搞实践再搞理论或者两者同时进行的人多,但正因为如果才成就了更实用更先进的理论。  
  理论是来用的,不是来争的,如果对你无用就是无用的理论。  
  如果你的思维方式是面向结构的,而不是面向对象,只要它够系统成熟,你完全可以编出很好的程序,甚至比面向对象还好。  
  不过你有没有考虑过,int是不是对象?它有没有属性集?  
   
  ///  
  微积分好像是Newton发明的,好像是为了解决力学方面的问题。我都不明白了OO的作用...。全是一群高人哪Top

42 楼yyy1020(yyy1020)回复于 2003-02-25 22:41:24 得分 0

一定要在running   time创建对象,因为操作系统从磁盘中将程序读入内存,完成定位等一系列操作过程之后,才会为程序分配内存。  
  而对象的本质是程序中占用内存的实体。  
  如果您的意思是在程序中把分配的内存都在程序文件中占用,在程序启动后直接映射进入内存,也未尝不可。不过这样的编译器是否有存在的价值还在未知之数。  
   
  http://www.csdn.net/cnshare/soft/11/11463.shtmTop

43 楼Frank001(Frank)回复于 2003-02-25 22:46:15 得分 0

楼上的对running   time的理解好象有偏差。Top

44 楼cpunion( int argc, char** argv )回复于 2003-02-26 19:01:39 得分 0

有人认为inside   the   c++   object   model一书被高估,我倒不这么认为,至少没看过这本书的人不会如此透彻的对C++底层机制明白。  
  能让你觉得容易看懂正是作者的高明之处。Top

45 楼J2eeLearner(重新出山)回复于 2003-02-26 19:28:13 得分 0

猪猪吹牛,越吹越牛!   嘻嘻~~Top

46 楼wingfiring(非典型秃子)回复于 2003-02-26 21:37:55 得分 0

同意cwanter(小菜)   的观点  
  “内存是在编译期分配的,初始化是在运行期。”  
  这个做法和在C当中没什么不同。构造函数总是在对象内存分配了以后才会被调用,C++特别的地方是构造函数总是会被调用。  
  例如:  
  string   str("text");str对象的地址(&str)和大小(sizeof(str))在编译期间是可以得到的,当然,地址是浮动地址。对于栈内对象来说,从我分析C汇编代码的经验来看,对象相对于栈顶的位置是编译期确定的,C++也是一样的,这些并不需要运行期来计算获得,而是直接影响生成的代码。所以可以认为对象的存储分配是静态的,也就是说:编译完成后,对象的存储位置和大小就是已知的了。然后就是调用构造函数来执行初始化动作,这个初始化不是简单的对成员赋值,而是建造对象这个大厦。到此为止,建立起一个对象可以分为两个过程:分配内存和建造对象。  
  需要明确的是:内存分配完成不是对象创建的完成!必须要到对象的初始化动作成功才能称之为对象创建完成。原因很简单:对象是封装了内部结构的,它必须完成它的复杂的内部构造才能成为一个对象。这一点,和简单数据类型、接口都是截然不同的。也是基于这个原因,在C++中,构造函数如果抛出异常则创建对象必然失败。  
  基于上面的分析,可以看出:分配内存是静态的。但是建造对象的过程呢呢?我认为这是个视角问题。如果我们把所有的不确定性因素从对象的创建中剥离出去,要求用对象的方法来实现,那么静态的创建对象是可能的。我们能够做到这一点,但我认为这不是个好方法。  
  于是像这样的C++类是不行的:  
  class   C  
  {  
  public:  
        C(type   arg);  
  };  
  必须设计成这样:  
  class   C  
  {  
  public:  
        //C(type   arg);不需要任何构造函数了  
        return_type   Init(type   arg);  
  };  
  他们的差别在于:程序员必须多写一行初始化代码,类似在C当中为变量初始化一样。虽然麻烦一点,但是也不完全是毫无益处。  
  但是从概念上来说,Init不是语言强制要求的,和一般的方法地位上是平等的:仅仅是一个方法。那么,意味着在我们初始化以前,所有的对象都是一样的。是不是可以打个比方:要表达“我想买一辆帕萨特”成为不可能事件,只能这样说:“我想买辆轿车。把这个轿车变成帕萨特。”很显然这样的思维方式我觉得是不大自然的,当然,也可能是受C++的“毒害”太深:)  
  至于dynamic我想应该是指new或类似的创建对象吧,这个内存分配可是没办法在编译的时候确定的。还有RTTI,静态?不用考虑也罢。Top

47 楼flyinger(风往北吹)回复于 2003-02-26 21:55:12 得分 0

我看了Inside   。。。。  
  只是感觉牙齿少了几颗而已!  
  呵呵!Top

48 楼ckacka(/*小红帽*/ckacka();)回复于 2003-02-27 16:16:22 得分 0

关注Top

49 楼heartup(心在跳)回复于 2003-02-27 17:06:33 得分 0

动态创建是因为有时候用户需要在运行时刻,创建一个一定类型(class)的对象.  
  因为这个类型在编译时刻是不知道的.所以动态创建机制是必要的.  
  Top

50 楼liu_feng_fly(笑看风云 搏击苍穹 衔日月)回复于 2003-02-27 17:26:53 得分 0

讨论的真激烈,占个位置先Top

51 楼cpunion( int argc, char** argv )回复于 2003-02-27 18:57:57 得分 0

楼主的意思我不太明白,对象是在执行期在内存中分配的一个实体,如果要在编译期就分配,能带来什么好处呢?  
   
  class   A  
  {  
        int*   p;  
  };  
   
  A::A()  
  {  
        p=new   int[10000];  
  }  
   
  A   a1,   a2,   a3,   a4,   a5;//定义实体  
   
  是不是说在执行期就执行A的构造函数,分配出那个数组呢?  
   
  那样的话,我这5个个对象要占用50000个字节?Top

52 楼SeekTruth(鹤舞白沙)回复于 2003-02-28 21:20:03 得分 0

 
   
      好贴,收藏....Top

53 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-01 23:26:14 得分 0

我也来说说   ^_^  
  前几天看了一篇帖子,突然觉得我想我们从另外一个方面来考虑这个问题,可能会稍微明白一点:  
   
  一个头文件:申明一个类,这个类里面定义了一个变量、一个函数可以用来打印出这个变量的值     ---------------     一共就这个两个元素,其中变量是   private   的,函数是   public   的(现在,我们暂时不考虑编译器的其他工作)  
   
  一个对应的   c++   文件:   #include   "头文件"   ,很明显,我们把他们编译,得到一个   .obj   文件,这个就是我们测试的对象  
   
  一个   main   文件:里面只有一个   main   函数   ----------------   里面的操作有申明出这个类对象,并且利用这个对象的打印函数打印出那个变量的值,编译,连接,一切   ok   生成的   .exe   文件一切正常  
   
  ————————  
          现在,我们的测试开始,我们在   main   函数里面添加一行   cout   语句,直接打印这个变量的值,“编译器”会说:“错误,……”  
  好的,我们换一个方法:  
          先把前面编译得到的   .obj   文件放到一个文件夹里,然后把改动过后的   main   文件放进来,,然后将那个头文件里面的   private   改成   public    
          编译,连接,成功,得到的   .exe   文件也一切正常  
          问题在于,我们那个   .obj   文件里面的那个变量明明是   private   的,我们只是稍微在头文件里面做了一点文章,似乎有点不可思议  
   
  ————————  
          前面只是一个花架子,不要砸我     ^_^  
          但是我们仔细一想,哦~~~原来对一个任意地址的访问都是“合法”的,尽管他可能不合我们的逻辑,因为一个纯代码代码级的东西本来就是一团混沌,没有什么规则可言(除了不同类型的差别以外),甚至我们也不愿意去设置什么规则,你想想,一个程序在运行的时候还要抽出时间去判断一个“变量”(加上引号的意思是这个阶段已经没有什么变量的概念了,我们只是把内存中的一段数据读入寄存器,然后操作,最后再放回到内存,好像还可以存盘哈~~),这个效率是惨不忍睹的,所以,我们的结论是:那个   .obj   文件里面没有任何规则,至少少了我们想像的那样的规则  
   
  ————————  
          结论出来了,在编译期的对象是真正的对象,在运行期的对象不过是一团混沌,和其他的变量之类的东西一团,没有界限  
          补充一下,其实什么虚函数表什么的,虽然是有序的(如果没有这个顺序,我们的   com   组件就无法实现,这点很重要),但是他们是编译期的,在运行期是没有的。  
          看看七年前的编译器,那时我还在上初中,那个   basica   ,再看看现在的,那个   visual   c++   .net   ,再看看那个   masm32   ,一个汇编的编译器,他们是不同语言的编译器,不同的时代(以前和现在),不同的层次(高级和低级),但是他们的目的一样,都把我们的语言变成机器代码,相同的功能  
          但是比较一下他们的各个方面(很笼统,我也无法例举出什么,水平太底,请原谅,但是至少我们可以感觉到他们的差别),那差别可大了,为什么?因为编译器,为我们做的事情有多少之分,比如   c++的编译器,我们在很多阶段的工作,编译器都明白我们所制定的规则,但是,当生米煮成熟饭了,一切规则就不复存在,因为在熟饭里面,我们的这个函数的操作只有调用某个函数,或者是操作某个变量,他不知道其他东西的存在,所以,如果我们在熟饭里面还要求什么“规则”的话,一切都只是浪费空间和时间(尽管完全可以实现这个所谓的规则,无非就是需要更多的空间和时间嘛~~)  
   
  ————————  
          也许现在还没有直接说到你的问题,不过,你换个角度来想,如果按照你的设想,我们恐怕就只能采用上面的笨办法了~~~~  
   
  ————————  
          很早我就关注你的这篇帖子了,不过不知道怎么来回答,现在随便说了说,也不敢说我的结论是正确的,如果不对,请指正!  
   
  ————————  
          发点牢骚:  
          说到   OO   ,虽然我是这个版的斑竹,不过也还是学习阶段,我发现这个版块的人气不好,也难怪,这是一门高深的学问,一方面是很多人没有真正理解这样的思想,无法在这里提问,另一方面是高手们都忙着赚分,很少来理会这些费时不讨好的问题(很惭愧,我的分数的很大一部分也都是在其他版块得到),呵呵,就说这个多吧~~~Top

54 楼mashimaro3600(爱吃白菜|教育免费)回复于 2003-03-01 23:55:41 得分 0

提Top

55 楼programmer200x(卧龙200x)回复于 2003-03-02 00:22:23 得分 0

讨论就会有正确的观点,当然也会有错误的观点了,  
  不过严重希望csdn里面多出现这种贴子.  
  那样有助于我们学习.严重关注.Top

56 楼yyy1020(yyy1020)回复于 2003-03-02 11:37:31 得分 0

引用    
  ckacka(小红帽)  
  /*       现在,我们的测试开始,我们在   main   函数里面添加一行   cout   语句,直接打印这个变量的值,“编译器”会说:“错误,……”  
  好的,我们换一个方法:  
          先把前面编译得到的   .obj   文件放到一个文件夹里,然后把改动过后的   main   文件放进来,,然后将那个头文件里面的   private   改成   public    
          编译,连接,成功,得到的   .exe   文件也一切正常  
  */  
   
  这说明在Link期,   主要通过头文件确定变量的private或public属性。但在Object   Pascal中   ,这种情况是不会发生的,这可能就是C++编译速度不如DELPHI的原因。Top

57 楼wingfiring(非典型秃子)回复于 2003-03-02 13:46:58 得分 0

to   ckacka(小红帽):  
  你所说的这些混淆了连接阶段和编译阶段,正如我们能够做到在C/C++当中去调用Fortran库一样。  
  private之类的访问控制是语言决定的,到编译结束就完成了,你这种黑客式的手法我想不会是C++的设计者所要考虑的。我不知道C++是否对连接有什么规定,就算有,我想应该也是很少的部分,连接器可不是单单为C++服务的.  
   
  “在编译期的对象是真正的对象,在运行期的对象不过是一团混沌,和其他的变量之类的东西一团,没有界限”,这显然是站不住脚的。不是说有什么机制来确定这一界限,而是变量在内存布局上仍然是有规律的。  
  对象当然是逻辑,在运行期间它总要为自己安排一个存身之所,但你不能因为没在其所在的内存位置上打上“对象”二字就认为他不能是对象。  
   
  虚函数表是确实存在的,虽然虚函数不一定要用虚函数表实现,但我用到的还都是这样实现的,包括VC,BCB,gcc。  
   
  再说.net,也不是不生成机器码,和Java一样,只是这个机器是个虚拟机.  
  basic很多是解释型的,根本就不编译.当然,也由很多编译型的Basic.  
   
  尽挑刺了,希望ckacka(小红帽)不会介意.俺是不针对人的.Top

58 楼brucegong(飞行猪)回复于 2003-03-02 14:52:58 得分 0

 
   
   
   
   
  我曾经说过不打算跟这个帖子了,看到这里实在是忍不住。  
   
   
   
   
  大家可不可以不要再用编译器的工作来看C++呢?是不是自己觉得发现了C++的什么秘密就很有成就感?C++目前的编译器在编译重载函数的时候根本就是改了名字的,所有的动态性都需要运行库的支持才可以实现。面向过程的编程风格的影响实在是太深了,而且目前的计算机好像没有在芯片级别上支持对象——面向对象的代码落实到二进制执行的时候,如果你有兴趣观看反汇编的执行过程,你会发现所谓的对象代码和面向过程的代码真的没有区别,那些运行库仅仅是给过程代码额外加了很多东西来保证对象的执行规则。  
   
  C语言不是执行边界检查的语言,可是这里的C++多多少少有点像执行边界检查的C语言了。同样是高级语言的pascal就执行了边界检查,确实是一门很适合初学者使用的语言。对于pascal,有几个人要求它和C的代码运行得一样快?而有有没有人要求C的程序编译之后运行起来比汇编代码执行起来还要快的?至于要求编译速度,那就更加离谱了——用户要求得到的仅仅是最终的执行软件,他用得着管你编译时花了一天还是两天吗?其实目前的多任务系统下的C++编译器编译的速度还是很可以接受的。偶曾有过一个编译器,编译160万行代码要用3个半小时——可是这又有什么关系呢?我们平时阅读代码挑出错误,调试的过程好像也没有比VC这样的“PnP”的工作环境下慢多少……如果什么东西都那么简单,要程序员干什么?  
   
  还有一句话不得不说:SQL语句执行起来效率惨不忍睹吧,可是它们真的很好用!还有ASN1语言,在电信里面描述协议如果用大家推崇的C语言,其程序简直惨不忍睹。我用了140行写出来的ASN1语言的程序,通过工具转换成为C语言之后有5000行!  
   
   
  C++仅仅是一个语言,它制定的是对象编程和代码重用这么一套源代码级别的软件工程范畴的规范而已。据我所知道的,C++并没有二进制级别的规范。现在正在打算扩展。不过,和大多数计算机的规范一样,都是先有产品后有规范的。corba和COM+加就是着眼于目前已经乱掉的二进制规范而提出来的一种通过专用接口来管理二进制代码使其能够实现二进制规范相似功能一种规范。它们的实现过程很是令人恼火的“低效率”,但是这是目前为了统一二进制规范所能作出的最大的努力了。  
   
  如果大家接触到了真正的对象编程工程,就会发现C++比起C语言来还是很好用的(当然C语言的简单直接也是C的有点)。我们没有理由因为C++叫了这么一个名字就整天想着它和C是不是应该详细比较一下。它完全可以叫一个特别的名字啊……大家或许可以拿它和其他的对象语言比较一下(实际上这样也没有意义,因为语言仅仅是一个工具)。  
   
  我们本来就比老外们落后了,大家如果将自己的学习时间浪费在了这些“编译速度”“执行效率”之类的争端上,C++这个强大的工具到了我们手里还是废铁一堆——因为用它的人愚昧啊!实践可以说明:改进算法和软件构架对软件速度的提高远远超过编译器的对于速度的贡献。大家还是努力提高自己吧。  
   
  ——这些话我也是对自己说的  
   
   
   
   
   
   
   
   
  Top

59 楼pigsir(小猪和C++)回复于 2003-03-02 15:43:20 得分 0

studyTop

60 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-02 15:58:49 得分 0

很高兴还有人愿意看完我这么长的一篇废话,先谢谢你们!   ^_^  
   
  to   yyy1020(yyy1020):  
          很赞同   stroustrup   观点,我也不愿意拿语言来互相比较。因为各自的特性不同,也各有长短。能用   asm   和   c++   比较么?很明显,在不同的应用上,我们会有不同的选择;甚至我们常常在   c++   中嵌套   asm   ,这也正是因为他们有互相不可替代的特性。硬是要说个孰好孰不好,反而是不好的。  
          我们现在谈的是   c++   ,所以最好不要和别的语言比较,呵呵!  
          说实话,我的   c++   学得很烂,更不说其他的语言了,我只能谈得这样肤浅,不好意思!  
   
  to   wingfiring(wingfire):  
          挑刺说不上,本来大家都是互相交流的,直接指出我的错误也是我学习的机会。尽管我不一定认为你的正确,但是至少我会对我自己的知识有所怀疑,我觉得抱着这样的心态和大家交流才会有所裨益,呵呵!  
          说说具体的:  
   
  “你所说的这些混淆了连接阶段和编译阶段,正如我们能够做到在C/C++当中去调用Fortran库一样。private之类的访问控制是语言决定的,到编译结束就完成了,你这种黑客式的手法我想不会是C++的设计者所要考虑的。我不知道C++是否对连接有什么规定,就算有,我想应该也是很少的部分,连接器可不是单单为C++服务的.”  
          你这段话要表达的意思我不太明白,但是至少我认为我没有混淆这两个阶段,从我的测试步骤可以看出来来的。  
   
  ““在编译期的对象是真正的对象,在运行期的对象不过是一团混沌,和其他的变量之类的东西一团,没有界限”,这显然是站不住脚的。不是说有什么机制来确定这一界限,而是变量在内存布局上仍然是有规律的。对象当然是逻辑,在运行期间它总要为自己安排一个存身之所,但你不能因为没在其所在的内存位置上打上“对象”二字就认为他不能是对象。”  
          我已经说过“所以,我们的结论是:那个   .obj   文件里面没有任何规则,至少少了我们想像的那样的规则”,很明显,我不否认规则的存在。  
          其实我想表达的观点是,任何   c++   的特性,仅仅是在编译阶段,在底层,大家都一样。比如:我们利用对象地址,通过虚函数来打印不同层次的类的变量,看似多态,事实上在编译阶段确实是多态,但一旦编译完成,这种“多态”也就不复存在,计算机只是单调得去调用一个个固定存在的“函数(抽象的)”。  
          同样的道理,你说到的的虚函数表,也仅仅是编译器为   c++   这门语言在编译期维护的,一旦成为机器码,这个也不复存在。  
          至于对象是不是逻辑,好像你的意思和我的一样嘛~~~。我并没有说内存上没有对象二字,这个对象就不存在呀~~我只是说这是一个便于我们理解事物的一个抽象的概念而已了!  
   
  “再说.net,也不是不生成机器码,和Java一样,只是这个机器是个虚拟机.  
  basic很多是解释型的,根本就不编译.当然,也由很多编译型的Basic.”  
          什么是编译,什么是虚拟机,什么是解释,我当然知道。  
          不过你可能不大了解   .NET   的真正实现。其实我也只是略知一二:  
  “再说.net,也不是不生成机器码,和Java一样,只是这个机器是个虚拟机.”  
          你的这个观点是错误的,说到   .NET   就不能不说说两个重要的概念   common   language   runtime   和   .NET   framework   class   library   ,他们就是   .NET   的很重要的要素,我们在   .NET   framework   class   library   下可以把我们的代码编译成   MSIL   然后在   .NET   framework   这样一个象你所说的一个虚拟机上运行。  
          但是要不要这样做,决定权在我们,我们可以不要求这样的实现,而是想以前一样生成一般的   pe   。而不是说只能生成什么   managed...  
          另外,.NET   也只是提供一个多语言交互的平台,而不仅仅是一个虚拟机。  
   
          呵呵,这个新玩意一出来我就比较关注,但是我精力有限(我是非计算机专业的,现在大四,很忙),所以理解也不一定正确。如有错误,望指正!  
   
  ————————  
  说到这里吧,欢迎继续……   ^_^Top

61 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-02 16:27:10 得分 0

to   brucegong(飞行猪):  
          呵呵,你说话的口气还真不小呀~~~开个玩笑,不过我觉得我们不应该说自己愚昧,顶多说自己不聪明罢了,何必那么极端呢?  
   
  “大家可不可以不要再用编译器的工作来看C++呢?是不是自己觉得发现了C++的什么秘密就很有成就感?”  
          ^_^   我没有说我有什么成就感,我只是在某些时候,在某些地方,按照某些人的想法,做了某些事情。  
   
        ***然而你这样的语句恐怕带有挑衅的意思吧?***  
   
        (正如前面所说,我只是一个学生,我只是按照我的爱好去学习,不可能为什么什么成就感而做什么事情)  
   
   
   
  “我们本来就比老外们落后了,大家如果将自己的学习时间浪费在了这些“编译速度”“执行效率”之类的争端上,C++这个强大的工具到了我们手里还是废铁一堆——因为用它的人愚昧啊!实践可以说明:改进算法和软件构架对软件速度的提高远远超过编译器的对于速度的贡献。大家还是努力提高自己吧。”  
          你这句话我不大赞同,这方面的落后是全方位的,如果我们只着眼于一些看的见,摸的着的东西,那么,没有根基的空中楼阁是站不起来的。  
          其实技术都是一样,研究低层次的难度总是大于研究高层次的难度。比如说到“湍流”,在力学上已经有了一定的概念,但是其中的数学问题却久久不能解决。  
          又比如说尊敬的   霍金、杨振宁   等基础理论物理学家,你能说他们研究的东西是在浪费时间么?  
          又比如说尊敬的   崔锦泰   ,他是   Texas   A&M   大学逼近论中心主任,也是小波研究方面的权威专家。我们知道,小波的理论非常深刻,但是一旦到了工程中,应用十分广泛。但是我们应该为了追求他的应用而仅仅是去使用他们提供的现成的研究成果么?显然这样做是目光短浅了些,恐怕……Top

62 楼J2eeLearner(重新出山)回复于 2003-03-02 16:51:03 得分 0

我只喜欢听猪猪吹牛,其他的不太感兴趣~    
   
  《深度探索》在我得眼里印象一直就不好,对于大部分人来说,除了能让你得到“一些底层细节,可以和别人炫耀”的东西之外,更实际更直接的东西少之又少!  
   
  而ckacka的例子   大概也就   和《深度探索》里面的内容大致一个层次。  
   
   
  这几天看Dessign   Pattern,   里面有一句话,大致这样是“系统的实现如果完全依赖于底层的具体细节(具体实现类),必然导致系统难以修改和拓展”。   用到这里大致也是如此~     呵呵   。   我们使用的仅仅是“C++”,更确切的是C++源程序,更多的人不必要关心底层的二进制代码排放等编译细节。我们只需要使用STL,而不需要了解STL的内部实现,候先生把“了解STL的原理和实作”作为了解STL的第二境界有点......,《STL源码剖析》,呵呵~~     :)  
   
   
  顺便说一下,昨天遇到这么个问题:  
  #include   <iostream>  
  #include   <string>  
   
  int   main(void)  
  {  
          string   s("david");  
   
          cout   <<   s.capacity()   <<   endl;  
          s.reserve(500);  
          cout   <<   s.capacity()   <<   endl;  
   
          return   0;  
  }  
   
  prints   out:  
  16  
  16  
   
  //    
  我查了一下源代码,   竟然  
    bastring  
  {  
      ...  
        void   reserve   (size_type)   {   }  
      ...  
  }  
   
  哈哈~~~Top

63 楼brucegong(飞行猪)回复于 2003-03-02 17:36:19 得分 0

 
   
   
  小红帽:  
   
   
  做编译器和做应用软件的过程是不一样的。  
   
  我并不歧视那些现在研究龙芯以及为龙芯编写代码的人们,相反,我尊重他们。我的水平不够,所以不能帮助他们,我很惭愧。  
   
  但是那些东西绝对不是玩一个编译器就可以玩好的。你可以翻翻计算机的英雄录,真正的高手全是数学上面的高手啊!!哪有我们这样的编码工人??  
   
   
   
   
   
   
   
  Top

64 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-02 19:02:24 得分 0

to   J2eeLearner(jinfeng_Wang):  
          不知道你有没有作过什么实实在在的东西,居然说出这样的话:  
  “《深度探索》在我得眼里印象一直就不好,对于大部分人来说,除了能让你得到“一些底层细节,可以和别人炫耀”的东西之外,更实际更直接的东西少之又少!”  
   
          如果你作过一些真正有应用的东西,你会发现很多无法解释的现象,除非我们去更深层地去发掘他们的本质。  
          举个例子,我们知道   MFC   中使用了大量的宏,功能非常强大,而使用却非常简单。但是如果我们仅仅使用   MFC   中的宏,而不去挖掘这些宏的定义步骤,如果遇到问题的话,恐怕就只能来这里问些毫无意义的问题了!  
          再说了,我说到的问题和《深度探索C++对象模型》没有任何关系。也不是一个层面上的  
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
  东西。  
  ~~~~  
   
  再次引用:  
  “《深度探索》在我得眼里印象一直就不好,对于大部分人来说,除了能让你得到“一些底层细节,可以和别人炫耀”的东西之外,更实际更直接的东西少之又少!”  
   
          ****我对你的这样的言语感到愤怒!!我上面说得很明白了,我没有什么炫耀的意思,要炫耀也不会向你这样的人炫耀。我会选择和那些明白我说什么的人讨论。请你自重。****  
   
   
  to   brucegong(飞行猪):  
          很高兴和你再次聊聊!  
          你自己也说到了“你可以翻翻计算机的英雄录,真正的高手全是数学上面的高手啊!!”,显然,你承认基础学科的重要性,也承认基础问题的重要性。  
          实话说了吧,我是学力学的,懂行的人都了解,我不多说了。虽然我的学习不怎么样,但是却让我深深知道了基本功的重要性。  
   
          现在的开发工具,开发语言都讲求高效,的确,很符合软件工程的需要。但是它掩盖的事实的本质,一旦这样的“编码工人”遇到无法解决的问题,最终让谁解决去???所以,我们要不断的学习,这样才不会成为“代码员”  
   
   
   
   
   
          现在   CSDN   上,至少在   c++   ,一些真正有应用的问题没有人解决,一些底层探讨的问题也被某些人认为是“炫耀”,……无语……  
          更有甚者说喜欢来这里听吹牛,何必这样浪费自己的生命呢?我来这里都是在各个版块看看有没有自己感兴趣的帖子,有时间也参与一些讨论,只不过参与的都是这个版块的帖子。学习的时间看看书,测试一些代码;休闲的时间就去打球,桑拿,喝酒什么的,也比在这里听吹牛好呀~~Top

65 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-02 19:17:44 得分 0

同时我要说明:  
  我赞同   merlinran(天行者)   和   earthharp(骄傲的石头)   看法!  
   
  我从来也不会过多的去钻研一些过于空泛的问题,甚至《深度探索C++对象模型》我也没有看完,我有很多计算机方面的书籍,还有很多数学,力学的专业书籍。不过我从来不会抽时间从头到尾的看,我只是在我需要的时候才去翻翻。但也决不会一点也不看。  
   
  至于《深度探索C++对象模型》书中的一些问题,我在其他很多类似的帖子的态度一向是不要钻牛角尖,很多东西是现在的很多编译器都没有实现的,仅仅是理论上的东西。至于这一点,你可以看看我以前参与过的讨论。  
   
  也许我的确有点激动,那是因为你们两个的不尊重造成。  
   
  我对待问题的态度一向都乐于请教,给别人解决问题的时候也是非常小心,绝对没有炫耀什么,或者是显示什么成就感?  
   
  这个问题已经脱离了本质,成为你们两个对我进行人身攻击的工具,我再次提醒你们,我感兴趣的是问题本身,而不是来对那些极度无聊的人身攻击来进行反击!Top

66 楼J2eeLearner(重新出山)回复于 2003-03-02 19:20:23 得分 0

呵呵,火气不小,也许我没有说清楚,我没有说你炫耀唉!  
  我是说《深度探索》教给人的东西呢,对于绝大部分人来说,仅限于炫耀,没有太大的直接用途,仅此而已!  
  另外,我加了一句,你的例子和《深度探索》里面的内容基本一个层次,所以我说你的例子没有太大的意思,讨论这个仅仅......  
   
  MFC我不熟悉,我很不喜欢这个东西,太多的宏定义。如果你是学习C++的,那么你就不要提MFC的宏。我到喜欢用borland的东西做一些东西,也许太“聪明”的缘故吧~。底层的东西,喜欢API。  
   
   
  我引用的那段来于《java与模式》话,也仅仅是为了说明,高层的实现不要和底层的细节牵涉太多。你无需对我愤怒和惊讶,讨论问题而已!呵呵~   昨天的个人小结中我是这样写的:只有在不停的讨论中才有进步。有人对你的东西发表意见应该是个很愉悦的事情,我对我做的一些事情找不到感兴趣的人感到沮丧!  
   
   
  另外,CSDN的实际问题没人解决?这不能怪我,嘿嘿!能力有限!  
  猪猪的话,总是能给我很多东西,所以我喜欢听他吹牛,有些人再多的话,我也不愿意多听的!呵呵~Top

67 楼yyy1020(yyy1020)回复于 2003-03-02 19:23:20 得分 0

个人观点:  
  即使是MS、Borland,在做开发工具的时候,也是以标准C++为参考,绝不会为C++而C++。  
  怎么样方便高效,就怎么做。最好的办法似乎是先把C++转换成汇编,然后使用汇编语言编译。  
  Top

68 楼yyy1020(yyy1020)回复于 2003-03-02 19:25:19 得分 0

纠正一下:  
  最后一句是:然后使用汇编语言编译器进行编译、链接。  
  Top

69 楼J2eeLearner(重新出山)回复于 2003-03-02 19:46:44 得分 0

好吧,我回答楼主的问题吧   ,呵呵,尽力  
   
   
   
  1   对象实现的主要原理,我并不陌生。  
      让我困惑的是为什么非得在running   time创建对象?在我看来,创建对象,同其它  
  c/c++全局数据结构一样,完全可以让编译器在compling   time创建,或者至少可以提供  
  一个选择策略,让用户自己选者是动态还是静态创建,这样一来,所谓seriesing完全多余,编译器自己就把事儿给干了--在c环境中,谁需要seriesing?(当然,c中动态创建的玩意也不宜直接写文件保存,但动态创建主要用于一些临时目的,完成主要功能的数据结构大多是compling   time创建。)  
      再次困惑:为什么非得在running   time创建对象?  
     
    //首先,C++支持多种程序设计方式,面向过程,面向抽象数据,面向对象,GP!  
  那么你的问题是有关“对象”问题的,属于面向对象的问题。   从对象的角度来看,都是有生命周期的,对于人这个对象来说,大家出生死亡的时间都是一样的。   最起码就需要考虑“突然”冒出一个对象   这么一个问题,例子如下:  
     
  class   base{}   ;  
  class   derived:public   base{}   ;  
   
  main()  
  {   ...  
      int   i   =random()   %   2;  
      base   *pbase;    
      if   (i   )   pbase   =new   base();  
            else   pbase=   new   derived();      
  }  
   
  这里的对象创建只有在运行的时候   才能决定,你怎么解决这个问题呢?   如果i的值是用户输入的呢?  
     
   
   
  2   构造函数用来初始话对象的成员,(默认构造函数什么也不做,对象的成员状态未定  
  ),这是大家都了然的。  
      可我们看到的构造函数仅仅用来初始话对象的成员,至少表面上看来如此,那为什么  
  不称构造函数为初始化函数?这样岂不更贴切?它的构造功能--准确的说构造对象的功  
  能体现在哪里?构造对象是要经过底层一系列的动作才能完成的,可我始终看不出构造函数干了什么。  
   
  //   名字叫什么需要争论么?你可以把“构造函数”叫做“析构函数”也没有关系,关键是他的实际意义没有改变就可以了,所以无论是“构造函数”还是“初始化函数”有什么关系呢?  
   
    你这段话,我都看不明白,你都说“构造函数用来初始话对象的成员”了,还问“构造对象的功能体现在哪里?构造对象是要经过底层一系列的动作才能完成的,可我始终看不出构造函数干了什么。”  
   
  另外,默认构造函数不是什么都不作,了解derived的构造函数里面的动作把!  
   
   
  Top

70 楼J2eeLearner(重新出山)回复于 2003-03-02 19:55:54 得分 0

对于人这个对象来说,大家出生死亡的时间都是一样的。  
  ===》  
  对于人这个对象来说,大家出生死亡的时间都是不一样的。Top

71 楼bobob(静思)回复于 2003-03-02 20:05:00 得分 0

好贴!!  
  我对c++只是一知半解,但是看到这么多高手如此激烈地讨论,我连饭都没有一直把帖子看完了。  
    J2eeLearner(jinfeng_Wang)   ,ckacka(小红帽)   ,   brucegong(飞行猪)   ,merlinran(天行者),   earthharp(骄傲的石头),向你们致敬!  
  Top

72 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-02 20:11:35 得分 0

 
   
   
   
  既然你有答案,为什么不早说呢????困惑……  
   
   
   
   
  “呵呵,火气不小,也许我没有说清楚,我没有说你炫耀唉!”  
  既然是误会那就化干戈为玉帛好了!   ^_^  
   
  其实要从语言本身的角度来解决这个问题,很简单。我窃以为你的例子有点耍滑头的意思(开个玩笑),因为你的回答主要是从该不该分配内存上说起,没有直接回答这个问题  
   
  我对这个问题从语言角度的回答是,可以考虑一下“模板类”这个非常重要的概念,他是必须在运行时刻才能决定整个对象的面貌的。甚至要在运行的时候才能确定应该需要多大的空间,怎么布局的空间!  
   
   
   
   
  Top

73 楼J2eeLearner(重新出山)回复于 2003-03-02 20:31:04 得分 0

直接的回答问题1   :  
   
  为什么一定要在编译期间决定哪?C如你说的在编译期间决定的么?  
   
  main()  
  {   ...  
      int   i   =random()   %   2;  
      char   *pc;    
      if   (i   )    
                pc=new(100);  
            else    
                pc=new(200);  
  }  
   
   
  既然有了malloc,就有他的用途,java里面的内存也是动态分配的阿,只是有了gc才无需自己回收而已!Top

74 楼J2eeLearner(重新出山)回复于 2003-03-02 20:33:29 得分 0

“模板类”这个非常重要的概念,他是必须在运行时刻才能决定整个对象的面貌的。甚至要在运行的时候才能确定应该需要多大的空间,怎么布局的空间  
   
  //  
  这段话的描述是不正确的,呵呵!   确切的说,一切都是在“编译期间”完成的,《深度探索》里面最后一章,也就是唯一的“有点实际用处”的地方了Top

75 楼LuoTing(罗亭)回复于 2003-03-02 21:28:08 得分 0

To   J2eeLearner:  
  说实话,你好象并没有理解楼主的真正意思。  
  楼主的本意是探讨隐藏在用户代码之后C++的真正实现部分,是如何实现的,但你的话仍停留在用户级代码的层面,相信你平时并不关心事物表面后边的细节。  
   
  To   飞行猪:  
  你的话和干涉别人的自由没有两样。  
  如果居然有人还觉得象楼主及真正想了解C++背后的朋友在此讨论这个主题是无聊的话,真是中国人的悲哀,奉劝阁下不要任意去干涉别人的自由,你如果想控讨设计,可以另辟贴子,自然有朋友关心。  
   
   
  //-------------------------------------------  
  我们所做的工作无非是两个方面:向上:讲究设计,向下:讲究效率,两者是完全没有冲突的。认识构造方法背后的细节,是有助于系统的优化设计;就象我们如果不了解vector的实现细节,就无法了解vector的真正特点,就会错误的去不断添减vector的元素。这些,从用户代码的书写来看是没有任何问题的,但这些都是屎!比屎还不如的代码。  
   
  真的很高兴看到有一些真正的高手在认真的探讨这些问题,而不仅仅是永远在学API,他们是中国做些真正东西的希望,也是唯一有机会去体会编程快乐的朋友;有些人学了100000000个api,10种语言,也许也不明白编译原理,这种人,如果让他去实现一个1000条/s数据处理的系统,可能吗?他会用尽了所有的API但仍无法完成任务。  
   
  说出来的话有些重,是因为我最讨厌浮华,尤其是浮华还不虚心。  
  Top

76 楼J2eeLearner(重新出山)回复于 2003-03-02 21:33:43 得分 0

http://expert.csdn.net/Expert/TopicView1.asp?id=1292976Top

77 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-02 22:15:00 得分 0

to   J2eeLearner(jinfeng_Wang):  
          现在回学校了,没有资料可查。  
          对于这个问题:  
   
  ““模板类”这个非常重要的概念,他是必须在运行时刻才能决定整个对象的面貌的。甚至要在运行的时候才能确定应该需要多大的空间,怎么布局的空间  
   
  //  
  这段话的描述是不正确的,呵呵!   确切的说,一切都是在“编译期间”完成的,《深度探索》里面最后一章,也就是唯一的“有点实际用处”的地方了”  
   
   
  如果我理解错了,先在这里向你表示歉意!  
  我会好好看看的,多谢指教!  
   
  嗬嗬!说实话,我还没有看过这章,因为我一直还没有怀疑过我的这个见解!Top

78 楼J2eeLearner(重新出山)回复于 2003-03-03 09:25:24 得分 0

不好意思,因为疏忽,总是把“连接期”也说成“编译期”!  
   
  模板的编译检查时间和你举的那个例子友异曲同工之妙,关键分清楚每个文件编译的时候都需要哪些内容,连接的时候又需要哪些内容,呵呵Top

79 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-03 11:49:37 得分 0

在编译期,我们只能得到一个模板的全部内容,编译期所能做到的仅仅是一个   evaluation   的工作;他把所有的实现放入了   .obj   文件,确切的说,编译期不能知道实际需要的空间  
   
  只能当连接器从   .obj   文件中提取了我们所需要的元素,形成了   .exe   文件后,我们才真正得到了运行中所需要的实际大小  
   
  一个简单的例子  
   
  我们定义   100   个模板,每个模板有   100   个“复杂的”成员函数  
  但是我的程序只使用这   10000   个函数其中的   1   个  
  这样:  
  switch   (   int   i   =   getchar()   )  
  {  
  case   1:   cla1->fun1();   break;  
  case   2:   cla2->fun2();   break;  
  .  
  ....  
  .  
  }  
   
  如果按照你的观点,大小在编译期就固定的话,那这个可执行文件启不是会异常的大?????Top

80 楼ckacka(/*小红帽*/ckacka();)回复于 2003-03-03 12:03:52 得分 0

呵呵,没有看到你前面的回复,把问题又说了一遍。  
   
  to   LuoTing(罗亭):  
          我很赞同你的观点!  
          侯先生在《mfc》里面也有类似的看法。(补充一下,我以前见过有些人拿《对象模型》来评论侯先生,这些人简直就是无知,难道他们不知道这本只是他翻译的么?听好了,这本书的作者是   lippman   !再说了,这本书非常有水平的,侯先生翻译的也很精彩)  
   
  “我们所做的工作无非是两个方面:向上:讲究设计,向下:讲究效率,两者是完全没有冲突的。认识构造方法背后的细节,是有助于系统的优化设计;就象我们如果不了解vector的实现细节,就无法了解vector的真正特点,就会错误的去不断添减vector的元素。”  
   
          这段话我很喜欢,可能比较符合我的观点吧!哈哈!!!!!!  
   
   
  --------------------------  
  争吵就到这里吧!  
   
  to   J2eeLearner(jinfeng_Wang):  
          如果前面我有所冒犯,还请原谅!   ^_^Top

81 楼JoshuaLi()回复于 2003-03-03 12:37:10 得分 0

“《深度探索》在我得眼里印象一直就不好,对于大部分人来说,除了能让你得到“一些底层细节,可以和别人炫耀”的东西之外,更实际更直接的东西少之又少!”   --再次对jinfeng_Wang表达相见恨晚之情,或为性情中人啊!  
  Top

82 楼J2eeLearner(重新出山)回复于 2003-03-03 12:58:55 得分 0

:)   ckacka,   给你一段别人的话  
   
   
  >   into   how   to   use   the   Return   Value   Optimization   and   was   suprised   by   one  
  >   of   the   results   I   received.     On   the   line   in   main:  
  >  
  >                   A   a4   =   a2   +   a3;  
  >  
  >   not   only   does   the   RVO   seem   to   work,   but   the   temporary   seems   to   never  
  >   get   created   at   all.     It   seems   to   me   that   the   compiler   must   somehow  
  >   detect   this   usage   and   somehow   combine   the   operator+   and   operator=  
  >   calls.     If   this   is   true   (which   to   me   it   seems   it   must),   is   there   a  
  >   good   book   on   compiler   construction   that   I   someone   could   recommend   that  
  >   would   show   the   details   of   this?  
   
  The   details   of   that   are   left   as   details   of   the   particular   compiler   and  
  linker   combination   you   are   using.   The   compiler   might,   as   intermediate   step,  
  have   the   call   graph   for   the   above   sequence,   but   the   optimizer   can   do   what   it  
  wants   as   long   as   the   results   are   still   defined.  
   
  float   v   =   a   +   b   +   c;  
   
  This   sequence   can   have   different   result   depending   on   the   order   the   +  
  operation   is   performed,  
  (a+b)   +   c  
  vs.  
  a   +   (b+c)  
   
  If   the   whole   calculation   is   done   in   full   precision   (what   that   may   be   for  
  platform   X),   it   can   have   drastically   different   result   from   the   intermediate  
  results   stored   in   less   precise   format.  
   
  There   is   one   widely   used   platform   where   this   immediately   is   true,   the   x86,  
  where   floating-point   stack   is   by   default   in   80   bit   precision   mode,   but   float  
  is   on   most   compilers   only   32   bits   wide.   If   the   full   expression   fits   into   fpu  
  stack,   it   can   easily   give   slightly   different   result   than   if   memory  
  temporaries   are   used.   But   the   Standard   allows   this   sort   of   stuff   to   take  
  place,   otherwise   it   would   be   next   to   impossible   to   write   compilers   which  
  could   come   up   with   reasonably   fast   binary   from   the   sourcecode.  
   
  If   the   =   and   +   operator   are   inlined,   the   optimizer   sees   the   operations   that  
  result   from   the   expression   and   optimizes   that   as   well   as   it   can   given   the  
  limitations   it   has   been   granted,   or   imposed   on,   whichever   has   nicer   ring   to  
  your   ear.   Those   operators   do   not   need   even   be   inlined,   there   are   compilers  
  which   actually   allocate   registers   and   generally   optimize   code   at   LINKING  
  time.   mipspro   7.4   and   visual   c++   .net   2003   for   instance   support   this   kind   of  
  code   generation.   When   not   explicitly   prohibitied,   it's   allowed.   ;-)   ;-)  
   
  So   your   question   is   in   hazard   of   being   off-topic   as   far   as   the   Standard   is  
  concerned.   This   is   pretty   much   implementation   dependant   behaviour   you   are  
  witnessing   here.   For   details   on   the   topic,   learn   a   bit   about   machine  
  instructions   your   platform   supports   and   then   take   long   looks   at   the   assembly  
  listings   your   compiler   generates,   you   will   learn   a   great   deal   of   information  
  you   will   have   absolutely   no   use   for.   ;-)  
  Top

83 楼flyinger(风往北吹)回复于 2003-03-03 13:51:51 得分 0

呵呵!Top

84 楼ywchh(神龙)回复于 2003-03-03 14:07:55 得分 0

看到各位的帖,很有学习的冲动!  
  向各位致敬·  
  ]Top

85 楼Schlemiel(维特根斯坦的扇子)回复于 2003-03-03 14:59:34 得分 0

to   fretre   ():  
  constructor是一个与其他方法不同的方法(当然destructor也是),你不能只从其中的代码来判断它做了什么事情。例如:  
  MyObject::MyObject()  
  {  
  //   do   nothing.  
  };  
  这个ctor应该解读为:  
  MyObject::MyObject()  
  {  
  //   do   something   about   object   contruction.  
  //   do   nothing   about   object   initialization.  
  }  
  对象的创建动作(例如内存的分配、虚表的排列)等工作是对用户透明的,但不能说ctor什么都没做。在你开始初始化之前,ctor已经做过很多事情了。如果你想确实地了解它做了些什么,很简单,在VC中看它的汇编码就可以了。  
  至于你的第一个问题,不知道你究竟是想说什么。可能我是受OO的毒太深,无法想象“不在running   time创建对象”是什么概念,想烦请你解释一下。Top

86 楼wingfiring(非典型秃子)回复于 2003-03-03 16:10:43 得分 0

to   ckacka(小红帽):  
  先说你的第一个Obj文件。  
  你编译的第一个文件虽然有类的定义,但是你没有定义任何对象。而类定义信息是不会保存到Obj文件中的,所以,你的第一个Obj文件根本是空的(__declspec(   dllimport   )之类那是另外一回事)。  
  你的第二个Obj文件才出现对象,所以你从来就不会引用什么第一个Obj文件里的对象。就象你第一个文件从来没有存在过一样。也谈不上什么public,private的问题,你完全可以把第一个Obj文件删除了。  
  对于Obj内部的情况,举个实际的例子来说把:  
  //f1.cpp: