前一段时间,我在 cnblogs 别人的博客中,谈到:

java 中的引用/指针,与 c++/C# 中的引用/指针不是一个概念.

Java 引用,相当于 c++ 指针(fun3)。Java 引用可以赋值 null, 而 c++ 引用 (见 fun2) 不能赋值 null,c++ 指针可以赋值 null(fun3).

Java 中,无 c++ 引用(fun2)对应的语法。

结果引起不必要的质疑,特此,写博客,对c++/java/c# 几种编程语言的指针、引用,进行比较,期望引起更多的人,对此有所关注。

从语法上看,三种开发语言中,C++ 的指针、引用,最为复杂,因此,下面的举例,都从 C++ 代码开始,然后与 java/c# 的语法进行比较。

1)  C++ 简单类型变量,有直接变量定义、指针定义、引用定义。

    int aa = 10;//c++
int &bb = aa;//c++
int *cc = &aa;//c++

上述三行代码,最后三个变量指向同一个数据。相比较而言,java/c# 都只有变量定义,无引用定义、指针定义。补充:感谢 xiaotie 、飞浪 的提醒:C#中是有指针的,在unsafe状态下,可以定义和使用指针。特更正。

2) C++ 函数调用参数,简单类型变量,有直接变量定义、指针定义、引用定义,后两个,在函数内部改变数据,退出函数,能看到改变后的数据。

void simple_by_val(int a, const int b)
{
a=15;
//b=13; //error C2166: l-value specifies const object //a=NULL; //good
//b=NULL; //error C2166: l-value specifies const object
} void simple_by_ref(int &a, const int &b)
{
a=25;
//b=23; //error C2166: l-value specifies const object //a=NULL; //good
//b=NULL; //error C2166: l-value specifies const object } void simple_by_pointer(int *a, const int *b)
{
*a = 35;
//*b = 33; //error C2166: l-value specifies const object a = NULL; //ok
b = NULL; //ok
}

java 没有这么多名堂,只有直接变量定义。C# 略为复杂一点,有引用,有 out 参数。

        static void M(int a, ref int b, out int c)
{
c = 13;
}

相比较而言,C# 的函数参数( ref int b), 类似于C++的函数参数( int &a),都是调用函数前要赋初值,在函数内部改变数据,退出函数,能看到改变后的数据。

而 C# 的 (out int c),在 C++/Java 中,无对应的语法。这个可以调用函数前,不赋初值。在 C# 之前,也很少见到这种语法,只在一些数据库的存储过程、函数定义中,见过类似语法。估计是从数据库编程语法中抄袭过来的语法。

特别注明:C# 的引用( ref int b),只是用在函数参数变量定义上,不能用在函数内部的局部变量中。C++ 中的引用( int &a),可以用在函数内部的局部变量中。

3)  C++ 的类对象变量定义语法,较为复杂,可以定义在stack 上(不用 new),可以定义在 heap(用 new)。

    CMyClass obj;                        //stack
CMyClass *p2 = new CMyClass(); //heap

java/C# 中,没有这么复杂,可以认为是上述两种“综合+简化”了。

4) 在 java/C# 中,如下用法是错误的,会报空指针异常;但是在 C++ 里是合法的。

    CMyClass obj;
obj.run();

在 C++ 中,

CMyClass obj;

以上一行代码已经调用了构造函数,完成了变量初始化。而在 java/C# 中,这一行代码相当于:

CMyClass obj = null;

5) C++ 中,stack 变量出了作用范围,内存自动回收;heap 变量,需要手工 delete。

java/C# 中,变量是空闲时自动回收的(理论上的),不是变量出了作用范围,就内存回收。

{
CMyClass obj; //stack
obj.test();
}//此处, stack 变量自动被 delete ,内存自动回收 {
CMyClass *p2 = new CMyClass(); //heap
p2->test();
} //此处,超出变量 p2 的作用范围,下面不能再用 p2 变量了,但是,内存并未释放,有内存泄露。

6) 以下代码在 C++ 中是正确的,在 java/C# 是错误的。在 java/C# 语法中,没有定义变量加 * 的,也不能用 -> 来调用类的函数或类的成员变量,也不能用 delete。

CMyClass *p1 = null;
CMyClass *p2 = new CMyClass();
p2->ab();
delete p2;
p2 = null;

7) 以下代码,在java/C# 语法中,是正确的,在 C++ 是错误的。C++ 中,这种赋值要用指针 (CMyClass *p1 = null;)。

CMyClass p1 = null;
CMyClass p2 = new CMyClass();

8) 以下代码,在 C++ 代码中,会调用“拷贝构造函数”、"等于号重载函数"。这两个函数,在 C++ 中,默认会由编译器自动生成。

    //C++
    CMyClass obj; //调用构造函数
CMyClass obj2 = obj; //调用拷贝构造函数
obj2 = obj; //调用 = 操作符重载函数

以上代码,大致相当于 java/C# 中的 克隆"clone"。但更隐蔽(初学者不知道调用了 C++ 构造函数、拷贝构造函数、= 操作符重载函数)、更复杂。java/C# 无操作符重载函数。

//C#
CMyClass obj = new CMyClass();
CMyClass obj2 = (CMyClass)obj.Clone();

而在 C# 中,Clone 函数并不会自动生成。在 Java 中,可以调用 super.clone() ---- Java 基类 Object 默认有一个 clone 函数。

在 C++ 中,默认会由编译器自动生成“拷贝构造函数”、"等于号重载函数",这一点,很多时候会造成问题,要特别注意。

在 C++ 中,函数返回值不要用 CMyClass ,这会造成不必要地调用“拷贝构造函数”、"等于号重载函数";也不要返回引用 CMyClass&, 对函数内局部变量的引用,退出函数后无法继续使用。而要返回指针 CMyClass *(最好用智能指针包装后的指针变量)。这一点很多初学者不明白。

但是 C++ 的 std:string 除外。std:string 的“拷贝构造函数”、"等于号重载函数"经过优化,拷贝后的变量,与拷贝之前的变量,内部使用相同的 char[] 数组,只有当一个 string 变量改变时,才会把 char[] 数组复制成两份。std:string 的“拷贝构造函数” 没有性能上损失,又比 string 指针减少了内存泄露,因此,对 std:string ,使用时尽量用 对象变量、对象引用、对象拷贝构造,避免使用 std:string 指针。

另,java/C# 的 String 变量不可改变(有其它类,比如 java StringBuilder类是可变的),C++ 的 string 变量可以改变。这个细微差异,很多人不明白。

9) C++ 引用语法,有一些是 Java/C# 程序员不知道的语法:

//C++
CMyClass &a1; //错误,C++ 引用变量定义的时候就要初始化;//Java/C# 对象变量,没有要求变量定义的时候,就要初始化 CMyClass &a1 = NULL; //错误,C++ 引用变量不能赋值 null CMyClass &a1 = new CMyClass(); //错误,C++ 引用变量不能赋值给一个 new 对象,这种情况,要用 C++ 指针。 //以下C++ 代码是正确的:
CMyClass a;
CMyClass &a1 = a; CMyClass *b =new CMyClass();
CMyClass &b1 = *b; //这种写法不常用。

10) Sun 自称 java 中消灭了 C++ 中万恶的指针,自己的对象变量,都是引用。做个比较:

C++ 引用不能赋值 null, 不能赋值 new XXX();C++ 指针可以赋值 null, 可以赋值 new XXX()。

C++ 引用对象通常在 stack 中,而C++ 指针 new 出来的对象则在 heap 中。

java/C# 中的对象变量,可以赋值 null, 可以赋值 new XXX()。java/C# 中的对象变量在 heap 中。

 

因此,java/C# 中的对象变量,更像是 C++ 中的指针,而不是 C++ 中的引用。

11) C++ 中,指针变量是一个 long 型整数,可以乱指的:

CMyClass *obj = (CMyClass *) 99;        //compile/run good, should not use    

如果我知道一个内存地址,就可以定义一个C++指针变量,指向这个内存地址。C++ 的“引用”没有这个功能。C#/Java 的对象变量更没有这个功能。

“指针乱指” 是 C++ 指针功能强大、灵活的体现(PC 上最早出现播放视频的时候,大概是 intel 486 CPU 时代,C++软件通常都直接写显存,据说这样速度更快),也是最容易出问题的地方。估计是因为这个原因,所以C#/Java 都去掉了这个功能。所谓“万恶的C++指针”,多半,也是指的是“指针乱指”。

12) C++ 有野指针,即已经删除对象,但指针还是指向删除对象,还可以继续操作,但运行结果不保证正确。

CMyClass *p = new CMyClass();
...//给 p 指向的内存赋值
delete p; //这时 p 仍然指向之前的内存地址,该内存地址数据,一般情况下、短时间内,并没有被清空或者覆盖,仍然可以读/写。这就是“野指针”。
p->run(); //运行结果可能正确,可能不正确,没有保证。 //此时指针 p 对应的内存,可能被下一个 new XXX() 代码,用了这个内存,因此,理论上讲,delete 之后的指针,不应再用来操作对象。 p= NULL; //将指针指向“空”,可以避免“野指针”问题。 p->run(); //这里会报运行时错误。也就是空指针异常。空指针异常在 java/c# 中都有。

C++ 中,delete 与将变量赋值 null , 理应放在一起,可以认为是一个“数据库事务”一样的,要么都成功、要么都失败。其实,delete 关键字,是由 C++ 标准定义的,标准中,完全可以要求: delete 所在行的代码,执行之后,把指针变量变成 null(C++ 标准的规范,很多都是规定编译器做什么,因此可以加这个规定)。这样可以避免野指针问题。可惜,C++ 标准,在这方面没有考虑周全。

另,有人抱怨,面试做题,看不是是 C++ 还是 Java、C# , 期望通过看本文,可以帮助一二。

---------------------------------------

欢迎大家下载试用折桂单点登录系统, http://zheguisoft.com

c++/java/c# 几种编程语言的指针、引用比较的更多相关文章

  1. Java的四种引用类型之弱引用

    先说结论: 首先,Java中有四种引用类型:强引用.软引用.弱引用.虚引用.-- 在 Java 1.2 中添加的,见 package java.lang.ref; . 其次,这几个概念是与垃圾回收有关 ...

  2. PHP、Java、Python、C、C++ 这几种编程语言都各有什么特点或优点

    PHP.Java.Python.C.C++ 这几种编程语言都各有什么特点或优点 汇编: C: Java: C#: PHP: Python: Go: Haskell: Lisp: C++: &l ...

  3. AES加密CBC模式兼容互通四种编程语言平台【PHP、Javascript、Java、C#】

    原文:AES加密CBC模式兼容互通四种编程语言平台[PHP.Javascript.Java.C#] 由于本人小菜,开始对AES加密并不了解,在网络上花了比较多时间查阅资料整理: 先简单从百度找来介绍: ...

  4. Java是面向对象的编程语言。它不仅吸收了C++语言的优点

    Java是面向对象的编程语言.它不仅吸收了C++语言的优点,而且摒弃了C++中难于理解的多继承和指针的概念.因此,Java语言具有功能强大.使用方便的特点.Java语言作为静态面向对象的编程语言的代表 ...

  5. java的五种数据类型解析

    不知道大家对java的简单数据类型是否了解,下面针对Java的五种类型简单数据类型表示数字和字符,进行详细的讲解和分析. 一.简单数据类型初始化 在Java语言中,简单数据类型作为类的成员变量声明时自 ...

  6. 用19种编程语言写Hello World

    用19种编程语言写Hello World 转载自:http://www.admin10000.com/document/394.html Hello World 程序是每一种编程语言最基本的程序,通常 ...

  7. 浅析c++/java/c#三大热门编程语言的运行效率

    从安全角度考虑,C#是这几中语言中最为安全的,它其中定义的相关安全机制很好的确保了系统的安全... 今天和同学们一起探讨下c++/java/c# 三大热门语言的运行效率情况,以及各自的用途. 估计有很 ...

  8. Java是一门面向对象编程语言的理解

    Java是一门面向对象编程语言. 不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征. Java语言作为静态面向对象编程语言的 ...

  9. 数百种编程语言,而我为什么要学 Python?

    是应用率最高.长期霸占排行榜的常青藤 Java?是易于上手,难以精通的 C?还是在游戏和工具领域仍占主流地位的 C++?亦或是占据 Windows 桌面应用程序半壁江山的 C#?…… 我想,每个人可能 ...

随机推荐

  1. clientTop、clientWidth、offsetTop、offsetWidth、scrollTop

    <div id="drag" class="drag">drag me</div> <script type="text ...

  2. 【同行说技术】iOS程序员从小白到大神必读资料汇总

    在文章<iOS程序员从小白到大神必读资料汇总(一)>里面介绍了很多iOS入门学习的资料,今天小编就发几篇技术进阶的文章,快来看看吧! 一.iOS后台模式开发指南 这个教程会教你在什么时候怎 ...

  3. HDU 4662 MU Puzzle 2013 Multi-University Training Contest 6

    现在有一个字符串"MI",这个字符串可以遵循以下规则进行转换: 1.Mx 可以转换成 Mxx ,即 M 之后的所有字符全部复制一遍(MUI –> MUIUI) 2.III 可 ...

  4. webpack的学习

    什么是webpack? 他有什么优点? 首先对于很多刚接触webpack人来说,肯定会问webpack是什么?它有什么优点?我们为什么要使用它?带着这些问题,我们来总结下如下: Webpack是前端一 ...

  5. android webview 遇到的问题:external/chromium/net/disk_cache/stat_hub.cc:216:

    今天也遇到这个问题,界面显示无法访问,Baidu吧,结果有些含糊其词,有的说加网络权限,我看了下我的, 有个 <uses-permission android:name="androi ...

  6. 嵌入式 hi3518平台获取网关

    </pre><pre code_snippet_id="495447" snippet_file_name="blog_20141024_1_70650 ...

  7. Windows 和 Linux 的IPC API对应表

    原文出处:http://blog.csdn.net/zhengdy/article/details/5485472                                           ...

  8. 序列化、反序列化和transient关键字的作用

    引言 将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口, ...

  9. mongo 安装

    mongo 安装: 1.按照 https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/ 安装 2.安装成功后创建用户 d ...

  10. LoadRunner error -27728

    错误现象1:Action.c(16): Error -27728: Step download timeout (120 seconds) has expired whendownloading no ...