C++ 是介于汇编语言与高级语言之间的一种“全能”语言。它的能力是其他任何基于VMA(冯-诺曼架构)计算机的高级程序设计语言无法望其项背的,而性能也只有C语言可与之伯仲。

然而长期以来,喜欢C++和憎恨C++的阵营,恶斗了三十多年,谁也说服不了谁。其中的一个重要原因是:C++的逻辑和语意难以分割,计算机学术界很难把它形式化(比如具有像Haskell那样的数学美), 这和量子力学里的不确定性类似,爱因斯坦就对此讨厌之极。

这里我不想评论两方的对错,但是我想就C++的一个最基本的概念,也是最重要的概念之一的“reference",作一番论述,看看是否说得通。

读者如果读过拙文“ http://blog.csdn.net/ly8838/article/details/38638491”,可能会对reference微妙的一面有所共鸣的。这里我想进一步谈谈reference的一些细节。

要想叙述reference,我们不得不从更基本的定义 - 直接对象(direct object)说起.

C++中,直接对象是“常规变量”(normal variable), 具有“值语意”(value semantics),和rvalue 语意。 这还没有引入reference,就已经陷入逻辑上“循环定义”的怪圈了。要想跳出,只有举例:

long x;

MyClass m;  // MyClass is a user defined class

上面xm都是“直接变量”,它们在内存中的区域可以不同:可以在程序的静态空间(全程变量),可以在工作堆栈内(自动变量),也可在动态空间内(间接地包含在母object中)。由于所在区域不同,这些直接变量对程序性能的特征影响很大(以后的博克会提及)。但是最重要的,是它们和传统的“基本型变量(primitive type variable)”在语法用法上的相似。这是C++为何会支持它的重要原因。

对于首先学习C#,JavaScript, 或其他现代语言的程序员来说,“直接变量”几乎没有对应的概念。而更加令人不解的是,在“动态空间(heap)”中,直接变量只能“间接”地存在。而能够“直接使用”动态变量"的唯一方法只有“指针”和“reference”. 这里又陷入了循环:解释直接变量时,又无法绕开“指针”和“reference”。

那么reference到底是什么呢?看看微基的解释,(http://en.wikipedia.org/wiki/Reference_(C%2B%2B)),它几乎也是同意反复,最后只有用“比喻”来解释。也就是说,不用“指针”,“内存地址”等概念就无法解释。

那么,通俗上的说法“reference 是变量的alias (同体异名?)”是否说得通呢?

我认为,对于初学者来说,alias可谓最好的“比喻”。请看:

int x = int(10);           // line1

int & r = x;                // line2: r is an alias of x

r++;                         // line3: x is now 11

r = 3;                       // line4: x is now 3

assert (&r == &x);     // line5: r points to x

我们看到,上面的程序显示,rx 几乎没任何区别,好像是形影相随,难分难舍。这正是C++的宗旨:让reference的变量和直接变量具有“等同”的语法,用法。

作为初级程序员来说,知道到这个用法也就够了,但是“一点点知识是危险的”。如果我们以为xr 是一个东西,那就错了:

首先,x 是“直接变量”,而r是间接变量,所以它们在语意上是完全不一样的(编译出来的代码大相庭径)。你可以说这与我无关,会应用就行了,这也不错,不过并不能高枕无忧:在另一个环境里,你可能就会因为不清楚object reference 和 direct object 的区别而出错,或是写出性能差别极大的程序。

从语意上看,line2 几乎等于 r = &x (取x的地址),无怪乎许多人认为 reference 其实就是指针, 而且line5证明它的确指着它的“直接变量”。知道这一点,对于下列代码很重要:

class X {…}

void myXFunction(X x) {…}

void myXFunction2(const X & x) {…}

如果认为X&X 的“alias”,而且用法一样, 那么你可能不需要myXFunction2,但是如果你知道X&的语意和X * 一样,你才会推论出myXFunction2的性能一般会比myXFunction好,特别是当X里面包含大量“成员”时,myXFunction2不用copy 内容,只需copy地址 (我们说这是浅拷贝- shallow copy), 而myXFunction必须传入的内容copy argument变量中(我们说这是深拷贝- deep copy)。

在这里,语意盖过了逻辑。const X &x 的用法,特别是语意,最好用指针来诠释才说得过去。

好吧,那就说reference是指针吧,可是它又不能解决上面程序line4的用法:

因为对一个指针赋值会使得它改变指向。若为指针,line4 会使得 指向地址为 的内存元,这和 alias 的概念又风马牛不相及。

幸运的是实际情况并非如此:没变(指向没变),倒是 变了,在这个用例中,对 的 alias 诠释从语法和语意上都双双胜过了指针诠释。

综上所述,reference 就像一个具有“波粒二象性”的光子, 它具有“pointer-alias” 二象性,不从语法-用法-语意的三方面理解,无法认识 reference 的真谛。

如果仅有二象也就罢了,OOP (C++ 支持OOP)有一个重要的概念,叫 polymorphism, 说的是一个“变量”其实可以是同时代表“基类”和其衍生类(derived  class):它既可以是A也可以是B(假设A是B的基类)(又是典型的量子悖论)。而这种 polymorphic 的变量,只能是指针和 reference,不可能是“直接变量”。这一特征又给 reference 加了另一顶帽子:polymorphic variable, 通俗说的话,它是具有同时拥有不同身份的“怪物”。这里的详情下次再谈论。

为什么polymorphic variable只能是指针reference呢?我个人认为,这无法用形式逻辑和常规逻辑来解释,只能用指针的性质和C++ 的object model内存结构来解释 - 这又是一个语意层面才能自圆其说的概念,是C++量子特性的另一佐证。以后我会用专文来诠释C++这一重大问题。

总之,一个reference 的概念,包含了三种完全不同的诠释,可以俗称为三位一体

  • Alias (同体异名)
  • Pointer (指针)
  • Polymorphic variable (多身份变量)(我不喜欢多状变量这一业界内常用的翻译,认为它完全是概念混淆的,错误的,这里没有“状态”,只有身份

到此可以做个总结,本文宗旨不是搬弄词汇,而是企图从逻辑,数学上诠释C++的一些基本概念,以便抛砖引玉,唤起你对C++的深层思考。

此文的结论是:

1)C++的一些基本概念不是形式逻辑和传统数学可以定义得清楚的。只有从“语意”上(编译目标代码)和“物理”上(计算机内存的结构)才能诠释。

2)C++的语意(程序的硬件表达),是理解C++的关键。其他的语言,如Java,C#, JavaScript等,更接近数理逻辑,不用太在意其“语意”,95%的都能理解。

3)不懂C++语意,对C++程序员的深化和提高,写出高质量,高性能的C++程序,有着不容忽略的负面影响。

杨镰:2014-8-18 西雅图

C++ Reference 的“三位一体”诠释的更多相关文章

  1. ASP.NET Core: You must add a reference to assembly mscorlib, version=4.0.0.0

    ASP.NET Core 引用外部程序包的时候,有时会出现下面的错误: The type 'Object' is defined in an assembly that is not referenc ...

  2. 【转】Django Model field reference学习总结

    Django Model field reference学习总结(一) 本文档包含所有字段选项(field options)的内部细节和Django已经提供的field types. Field 选项 ...

  3. (转) Qt 出现“undefined reference to `vtable for”原因总结

    由于Qt本身实现的机制所限,我们在使用Qt制作某些软件程序的时候,会遇到各种各样这样那样的问题,而且很多是很难,或者根本找不到原因的,即使解决了问题,如果有人问你为什么,你只能回答--不知道. 今天我 ...

  4. 重新诠释的OSGi规范

    上周五部门开会讨论新一代产品(基于.net Winform)的设计规范,从设计规范慢慢讨论到体系结构等架构存在的问题,诸如菜单.工具条.状态条.界面布局等不能实现配置化和自动化,子系统之间拥有强依赖, ...

  5. undefined reference to `__android_log_print'

    使用android studio 编写NDK代码时出现错误:undefined reference to `__android_log_print' 解决办法: eclipse       andro ...

  6. CentOS 6.5 编译 PHP-7 报错:undefined reference to `libiconv_open 无法编译 PHP libiconv

    ./configure --with-mysql=/backup/mysql --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zli ...

  7. Qt - 错误总结 - 在自定义类头文件中添加Q_OBJECT 编译时报错(undefined reference to ‘vtable for xxThread)

    错误提示:在添加的QThread子类头文件添加Q_OBJECT时,编译程序,出现"undefined reference to 'vtable for xxThread'"错误提示 ...

  8. Conditional project or library reference in Visual Studio

    Conditional project or library reference in Visual Studio In case you were wondering why you haven’t ...

  9. Qt经典出错信息之undefined reference to `vtable for classname

    原文链接:Qt经典出错信息之undefined reference to `vtable for classname 这个出错信息太常见了,用过Qt两个月以上的朋友基本上都能自己解决了,因为太经典了, ...

随机推荐

  1. 利用python分析nginx日志

    最近在学习python,写了个脚本分析nginx日志,练练手.写得比较粗糙,但基本功能可以实现. 脚本功能:查找出当天访问次数前十位的IP,并获取该IP来源,并将分析结果发送邮件到指定邮箱. 实现前两 ...

  2. Spark如何解决常见的Top N问题

    需求   假设我们有一张各个产品线URL的访问记录表,该表仅仅有两个字段:product.url,我们需要统计各个产品线下访问次数前10的URL是哪些?   解决方案   (1)模拟访问记录数据   ...

  3. Asp.net 字体样式

    在页面中使用到字体样式  “微软雅黑“,在静态页面中显示正常,但在asp.net页面中字体无效,此时只需把字体修改为“Microsoft YaHei";

  4. leetcode实现 “10001”+“1011” 返回二进制相加的结果

    https://oj.leetcode.com/problems/add-binary/ 实” 1 public class Solution { public String addBinary(St ...

  5. TCP 的那些事儿(上)

    TCP是一个巨复杂的协议,因为他要解决很多问题,而这些问题又带出了很多子问题和阴暗面.所以学习TCP本身是个比较痛苦的过程,但对于学习的过程却能让人有很多收获.关于TCP这个协议的细节,我还是推荐你去 ...

  6. 上海Uber优步司机奖励政策(1月25日~1月31日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  7. Apache-POI操作Excel的一些小技巧

    Apache-POI操作Excel将合并后的单元格全部填充为相同数据的一个实例. private static void fillMergedRegion(final Sheet sheet) { f ...

  8. IntelliJ IDEA自用快捷键 转载

    最常用快捷键- 未分类 command Binding Description defeat - Ctrl+/ 代码提示 No - Ctrl+Alt+L 格式化代码   - Ctrl+B 快速打开光标 ...

  9. [kuangbin带你飞]专题十 匹配问题 二分图多重匹配

    二分图的多重匹配问题不同于普通的最大匹配中的"每个点只能有最多一条边" 而是"每个点连接的边数不超过自己的限定数量" 最大匹配所解决的问题一般是"每个 ...

  10. CMDLINE的解析

    在linux的config文件中有一个特殊的宏定义CMDLINE,以前也一直在使用这个宏的参数,但是真正这个宏的解析和使用却不怎么明确.这次有机会多对它有些了解,不妨把这个浅显的认识说出来,记下来. ...