注册 | 登录
收藏 | 帮助
热门文章
编辑推荐
相关文章  
模块复用——c++类、dll和com
获取ACCESS2000数据库中的所有表
C++语言常见问题解答(1)
C++语言常见问题解答(2)
C++语言常见问题解答(3)
在c++程序中重启自己的一种方法
您现在的位置: 顶尖设计 >> IT学院 >> 编程开发 >> C >> 文章正文
C++语言常见问题解答(4)
作者:中译者:叶秉哲  来源:永远的UNIX  点击:  更新:2006-12-19
简介:
 y = tmp; 
        } 
 
假如我们想交换 float、long、String、Set 和 FileSystems,我们还得写那些 
大致看起来都一样、只有型态不同的程式码,有够烦人。这种不花脑筋的重复性工作 
,正是电脑的专长,於是我们想出了 function template: 
 
        template 
        void swap(T& x, T& y) 
        { 
          T tmp = x; 
          x = y; 
          y = tmp; 
        } 
 
每次我们以一组型别来使用 "swap()",编译器会找到上面这定义,并造出另一个 
"template function" ,来当作它的「案例」(instantiation)。譬如: 
 
        main() 
        { 
          int    i,j;  /*...*/  swap(i,j);  // 案例化 "int"    的 swap 
          float  a,b;  /*...*/  swap(a,b);  // 案例化 "float"  的 swap 
          char   c,d;  /*...*/  swap(c,d);  // 案例化 "char"   的 swap 
          String s,t;  /*...*/  swap(s,t);  // 案例化 "String" 的 swap 
        } 
 
(注意:"template function" 是 "function template" 实体化之後的案例。) 
 
======================================== 
 
Q119:"class template" 的语法/语意是什麽? 
 
考虑像是个整数阵列的容器类别: 
 
        // 这会放在像是 "Array.h" 的标头档中 
        class Array { 
        public: 
          Array(int len=10)                  : len_(len), data_(new int[len]){} 
         ~Array()                            { delete [] data_; } 
          int len() const                    { return len_;     } 
          const int& operator[](int i) const { data_[check(i)]; } 
                int& operator[](int i)       { data_[check(i)]; } 
          Array(const Array&); 
          Array& operator= (const Array&); 
        private: 
          int  len_; 
          int* data_; 
          int  check(int i) const 
            { if (i < 0 || i >= len_) throw BoundsViol("Array", i, len_); 
              return i; } 
        }; 
 
如同前述的 "swap()" ,一再为 float、char、String、Array-of-String 等等来重 
复设计 Array 类别,是很烦人的。 
 
        // 这会放在像是 "Array.h" 的标头档中 
        template 
        class Array { 
        public: 
          Array(int len=10)                : len_(len), data_(new T[len]) { } 
         ~Array()                          { delete [] data_; } 
          int len() const                  { return len_;     } 
          const T& operator[](int i) const { data_[check(i)]; } 
                T& operator[](int i)       { data_[check(i)]; } 
          Array(const Array&); 
          Array& operator= (const Array&); 
        private: 
          int len_; 
          T*  data_; 
          int check(int i) const 
            { if (i < 0 || i >= len_) throw BoundsViol("Array", i, len_); 
              return i; } 
        }; 
 
不像 template function 那样,template classes(案例化的 class template)必 
须将那些用来案例化的参数型态明示出来: 
 
        main() 
        { 
          Array           ai; 
          Array         af; 
          Array         ac; 
          Array        as; 
          Array< Array >  aai; 
        }              // ^^^-- 注意这空格;不要用 "Array>" 
                       //       (编译器会把 ">>" 看成单一的元素) 
 
======================================== 
 
Q120:什麽是「参数化型别」(parameterized type)? 
 
另一种 "class template" 的说法。 
 
「参数化型别」是一种型别,它被另一个型别或数值所参数化(parameterized)了。 
像 List 是一个型别 ("List") ,它被另一个型别 ("int") 所参数化。 
 
======================================== 
 
Q121:「泛型」(genericity)是什麽? 
 
另一种 "class template" 的说法。 
 
不要和「一般化」(generality,指不要过於特定的解题)弄混了,「泛型」指的是 
class template。 
 
 
======================= 
■□ 第20节:程式库 
======================= 
 
Q122:怎样拿到 "STL"? 
 
"STL" 代表 "Standard Templates Library",标准模版程式库。取得法: 
 
STL HP official site:   ftp://butler.hpl.hp.com/stl 
STL code alternate:     ftp://ftp.cs.rpi.edu/stl 
STL code + examples:    http://www.cs.rpi.edu/~musser/stl.html 
 
STL hacks for GCC-2.6.3 已经在 GNU libg++ 2.6.2.1 或更新版本里了(可能较早 
的版本也有)。多谢 Mike Lindner。 
 
======================================== 
 
Q123:怎样 ftp 到 "Numerical Recipes" 附的程式? 
 
它是用卖的,把它放到网路上散布是违法的。不过它只需 $30 美元而已。 
 
======================================== 
 
Q124:为什麽我的执行档会这麽大? 
 
很多人对这麽大的执行档感到惊讶,特别是当原始码只有一点点而已。例如一个简单 
的 "hello world" 程式居然会产生大家都想不到的大小(40+K bytes)。 
 
一个原因是:有些 C++ 执行期程式库被连结进去了。有多少被连结进去,就要看看 
你用到多少,以及编译器把程式库切割成多少块而定。例如,iostream 很大,包含 
一大堆类别及虚拟函数,即使你只用到一点点,因为各元件之间的交互参考依存关系 
,可能会把整个 iostream 程式码都塞进来了。(【译注】如果 linker 做得好的话 
,应该能把完全用不到的元件 object code 砍掉,不随之塞入你的执行档中。) 
 
不要用静态的,改用动态连结的程式库版本,就可以使你的程式变小。 
 
欲知详情,请看看你的编译器手册,或是寻求厂商的技术支援。 
 
 
=============================== 
■□ 第21节:特定系统的细节 
=============================== 
 
Q125:GNU C++ (g++) 把小程式造出大大的执行档,为什麽? 
 
libg++(g++ 用到的程式库)可能在编译时带有除错的资讯(-g)。有些机器上,不 
带除错资讯地重新编译它,会省下很大的磁碟空间(~1 MB;缺点是:不能追踪到 
libg++ 的呼叫)。仅仅 "strip" 掉执行档,比不上先用 -g 重新编译,再 "strip" 
掉 a.out 档来得有效。 
 
用 "size a.out" 来看看执行码的程式与资料区段到底占了多大空间,而不要用 
"ls -s a.out" 这种包括了符号表格(symbol table)的方式。 
 
======================================== 
 
Q126:有 YACC 的 C++ 文法吗? 
 
Jim Roskind 是 C++ 的 YACC 文法作者,它大体上和部份 USL cfront 2.0 所实作 
出来的语言相容(没有 template、例外、执行期型态识别功能)。这份文法有些地 
方和 C++有细小而微妙的差别。 
 
它可用 anonymous ftp 到下列地方取得: 
 * ics.uci.edu (128.195.1.1) in "gnu/c++grammar2.0.tar.Z". 
 * mach1.npac.syr.edu (128.230.7.14) in "pub/C++/c++grammar2.0.tar.Z". 
 
======================================== 
 
Q127:什麽是 C++ 1.2?  2.0?  2.1?  3.0? 
 
这些不是“语言”的版本,而是 cfront 这个由 AT&T 做出来的、最早的 C++转译程 
式的版本编号。以这编号来“代表”C++ 语言的演进,已经是公认的惯例了。 
 
“非常”粗略地讲,主要的特徵有: 
 * 2.0 包含多重/虚拟继承,以及纯虚拟函数。 
 * 2.1 包含半巢状 (semi-nested) 类别,及 "delete [] 阵列指标"。 
 * 3.0 包含全巢状 (fully-nested) 类别、template 和 "i++" vs "++i"。 
 * 4.0 将包含例外处理。 
 
======================================== 
 
Q128:如果签名编码标准化了,我能否将不同厂商编译器产生的程式码连结起来? 
 
简短的回答:可能不行。 
 
换句话说,有人希望标准化的签名编码规则能并入拟议中的 C++ ANSI 标准,避免还 
要为不同厂商的编译器购买不同版本的物件程式库。然而不同的系统实作中,签名编 
码的差异性只占一小部份而已,即使是在同一个基台(platform)上。这里列出一部 
份其他的差异处: 
 
1) 成员函数隐含的引数个数和型态。 
   1a) 'this' 有被特殊处理吗? 
   1b) 传值的指标放在哪里? 
2) 假设有用到 vtable 虚拟表格的话: 
   2a) 它的内容及配置? 
   2b) 多重继承时,'this' 在何处/如何调整? 
3) 类别如何配置,包含: 
   3a) 基底类别的位置? 
   3b) 虚拟基底类别的处理? 
   3c) 虚拟表格指标的位置,如果有用虚拟表格的话? 
4) 函数的呼叫惯例,包含: 
   4a) 呼叫者还是被呼叫者负责调整堆叠? 
   4b) 实际参数放到哪里? 
   4c) 实际参数传递之顺序? 
   4d) 暂存器如何存放? 
   4e) 传回值放到哪里? 
   4f) 对传入/传回 struct 或 double 有无特殊的规定? 
   4g) 呼叫末端函数(leaf function)有无特殊的暂存器存放规定? 
5) run-time-type-identification 如何配置? 
6) 当一个例外被 throw 时,执行期的例外处理系统如何得知哪一个区域物件该被解 
   构? 
 
 
======================================= 
■□ 第22节:其他的技术和环境的事项 
======================================= 
● 22A:其他的技术事项 
======================== 
 
Q129:为什麽有 static 资料成员的物件类别产生了 linker 错误? 
 
Static 的资料成员必须外显地在唯一的模组中定义。 
                     ^^^^^^  ~~~~~~^^^^  ^^^^ 
【译注】这句话要逐字细读。原文是:Static data members must be 
        explicitly defined in exactly one module. 
 
譬如: 
        class Fred { 
        public: 
          //... 
        private: 
          static int i_;  // 宣告 static 资料成员 "Fred::i_" 
          //... 
        }; 
 
Linker 会告诉你 "Fred::i_ is not defined(未定义)" ,除非你在任何一个(且 
唯一)原始档中定义(而非宣告)了 "Fred::i_" : 
 
        int Fred::i_ = 某个会产生 int 的运算式; 
或是: 
        int Fred::i_; 
 
通常我们会在 "Fred.C" 档中定义 "Fred" 类别的 static 资料成员(或 "Fred.cpp" 
等等你使用的副档名)。 
 
======================================== 
 
Q130:"struct" 和 "class" 关键字差别在哪? 
 
struct 的成员和基底类别, 都是预设为 public 的,而 class 则预设为 private。 
注意:你应该“明显地”把基底类别设为 public、private 或是 protected,而不 
要依赖预设值。 
 
除此之外,两者的功能是相等的。 
 
======================================== 
 
Q131:为什麽不能以函数的传回值来多载(overload)它? 
 
如果你同时宣告了 "char f()" 及 "float f()" ,编译器会给你个错误讯息,因为 
呼叫 "f()" 会造成模拟两可的情况。 
 
======================================== 
 
Q132:什麽是「持续性」?什麽是「持续性物件」? 
 
一个持续性物件 (persistent object),在创造它的程式执行结束後,仍可存活下来 
。它甚至可存活於不同的父程式,存活於磁碟系统、作业系统、甚至於作业系统所处 
的硬体上。 
 
持续性物件的困难在於:如何有效地在次储存体中,存放它们的运作行为(method) 
及资料位元(以及所有成员物件的资料和运作行为,及它们所有的成员物件、基底类 
别……等等)。这一切都得自己来做的话,可不是件容易的事。在 C++中,你就得自 
己来。C++/OO 的资料库系统,会替你把这些机制都隐藏起来。 
 
======================================== 
 
Q133:为什麽浮点数 (floating point) 这麽不精确?为什麽这段程式不会印出 0.43? 
 
        #include 
 
        main() 
        { 
          float a = 1000.43; 
          float a = 1000.0; 
          cout << a - b << '\n'; 
        } 
 
(附注,有些 C++ 环境下会印出 0.429993) 
 
声明:受进位/舍位/近似值之苦,其实并不是 C++ 的问题,而是电脑科学界的问 
题。不过还是一直有人在 comp.lang.c++ 里发问,所以我给你一个答案意思一下。 
 
答案:浮点数本来就是个近似值。在 IEEE 的 32 位元浮点数标准里,有 1 位元的 
正负号,8 位元的指数,23 位元的假数。因为正规化後的二进位假数都会变成像是 
1.xxxxx... 的型式,所以头一项的 1 不予计入,就能得到 24 位元的有效假数。 
1000.43(以及其他很多很多数字)都不是 float 或 double 的表示法,其实 
1000.43 的位元内容是这样子的('s' 代表正负号,'e' 代表指数,'m' 代表假数) 
: 
 
    seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm 
    01000100011110100001101110000101 
 
假数移位後变成 1111101000.01101110000101 或是 1000 + 7045/16384。 
分数部份为 0.429992675781。 
float 的假数占 24 位元,所以你只得到 16M 分之一的精确度。 
double 有较高的精确度(53 位元的假数)。 
 
========================== 
● 22B:其他环境下的琐事 
========================== 
 
Q134:有任何 TeX 或 LaTeX 的巨集,能处理 "C++" 的留白效果(spacing)吗? 
 
有的,底下列出两个: 
 
\def\CC{C\raise.22ex\hbox{{\footnotesize +}}\raise.22ex\hbox{\footnotesize +}} 
 
\def\CC{{C\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}} 
 
======================================== 
 
Q135:在哪儿可拿到 C++2L

上一页  [1] [2] [3] 下一页






  • 上一篇文章:
  • 下一篇文章:
  • 分享此文:该页面添加到 Mister Wong 添加到雅虎Yahoo!收藏 Add to:Del.icio.us Post to Furl Digg this 添加到Google书签 reddit spurl blogmarks 365Key 评论  收藏  分享  打印
     我来说两句
    姓名:       验证码:   
    主页: 
    评分: 1分 2分 3分 4分 5分
    本频道近期热评文章:
      关于我们 | 联系我们 | 站点地图 | 广告投放 | 友情链接 | 在线留言 | 版权申明
    版权所有 © 2004-2007 顶尖设计(bobd.cn)
    未经授权禁止转载,摘编,复制本站内容或建立镜像. 沪ICP备07504942号 
    网络110
    报警服务