Tim

一枚野生程序员~

  • 主页
  • 分类
  • 标签
  • 归档
  • 关于
所有文章 工具

Tim

一枚野生程序员~

  • 主页
  • 分类
  • 标签
  • 归档
  • 关于

指针与引用

阅读数:次 2018-04-08
字数统计: 2.1k字   |   阅读时长≈ 8分

1970年,美国贝尔实验室的Ken Thompson将BCPL进行了修改,并为它起了一个有趣的名字“B语言”。意思是将BCPL语言煮干,提炼出它的精华。并且他用B语言写了第一个UNIX操作系统。 而在1973年,B语言也给人“煮”了一下,美国贝尔实验室的D.M.RITCHIE在B语言的基础上最终设计出了一种新的语言,他取了BCPL的第二个字母作为这种语言的名字,这就是C语言。 为了使UNIX操作系统推广,1977年Dennis M.Ritchie 发表了不依赖于具体机器系统的C语言编译文本《可移植的C语言编译程序》。即是著名的ANSI C。而C++就是以ANSI C为基础进行开发的,本文重在C的指令和C++的引用的区别。

产生的过程

1970年,AT&T的Bell实验室的D.Ritchie和K.Thompson共同发明了C语言。研制C语言的初衷是用它编写UNIX系统程序,因此,它实际上是UNIX的“副产品”。20世纪70年代中期,Bjarne Stroustrup在剑桥大学计算机中心工作。他使用过Simula和ALGOL,接触过C。他对Simula的类体系感受颇深,对ALGOL的结构也很有研究,深知运行效率的意义。既要编程简单、正确可靠,又要运行高效、可移植,是Bjarne Stroustrup的初衷。以C为背景,以Simula思想为基础,正好符合他的设想。1979年,Bjame Sgoustrup到了Bell实验室,开始从事将C改良为带类的C(C with classes)的工作。1983年该语言被正式命名为C++。

函数重载

方法重载 (overload)
C++允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading),借助重载,一个函数名可以有多种用途。
永远记住一点:函数重载只与参数列表有关,与返回值类型无关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int fun(int a,int b){
return 0;
}

int fun(int a,char b){
return 0;
}

void fun(){
}

int fun(int a, int b, int c){
return 0;
}

使用 objdump -S a.out 命令便可以通过a.out查看编译器编译出的汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
0000000000400674 <_Z3funii>:
400674: 55 push %rbp
400675: 48 89 e5 mov %rsp,%rbp
400678: 89 7d fc mov %edi,-0x4(%rbp)
40067b: 89 75 f8 mov %esi,-0x8(%rbp)
40067e: b8 00 00 00 00 mov $0x0,%eax
400683: c9 leaveq
400684: c3 retq

0000000000400685 <_Z3funic>:
400685: 55 push %rbp
400686: 48 89 e5 mov %rsp,%rbp
400689: 89 7d fc mov %edi,-0x4(%rbp)
40068c: 89 f0 mov %esi,%eax
40068e: 88 45 f8 mov %al,-0x8(%rbp)
400691: b8 00 00 00 00 mov $0x0,%eax
400696: c9 leaveq
400697: c3 retq

0000000000400698 <_Z3funv>:
400698: 55 push %rbp
400699: 48 89 e5 mov %rsp,%rbp
40069c: c9 leaveq
40069d: c3 retq

000000000040069e <_Z3funiii>:
40069e: 55 push %rbp
40069f: 48 89 e5 mov %rsp,%rbp
4006a2: 89 7d fc mov %edi,-0x4(%rbp)
4006a5: 89 75 f8 mov %esi,-0x8(%rbp)
4006a8: 89 55 f4 mov %edx,-0xc(%rbp)
4006ab: b8 00 00 00 00 mov $0x0,%eax
4006b0: c9 leaveq
4006b1: c3 retq

00000000004006b2 <main>:
4006b2: 55 push %rbp
4006b3: 48 89 e5 mov %rsp,%rbp
4006b6: b8 00 00 00 00 mov $0x0,%eax
4006bb: c9 leaveq
4006bc: c3 retq

由此可见g++编译器在编译cpp源文件的时候,对于同名称的函数做了区分,添加了相应的函数修饰,修饰之后的函数名称不同,所以是可以区分的!
同样的道理我们可以看看C语言是否支持函数重载:

1
2
3
4
5
6
7
8
9
#include<stdio.h>

void fun(int a, int b){

}

int main(){
return 0;
}

对应的汇编代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0000000000400474 <fun>:
400474: 55 push %rbp
400475: 48 89 e5 mov %rsp,%rbp
400478: 89 7d fc mov %edi,-0x4(%rbp)
40047b: 89 75 f8 mov %esi,-0x8(%rbp)
40047e: c9 leaveq
40047f: c3 retq

0000000000400480 <main>:
400480: 55 push %rbp
400481: 48 89 e5 mov %rsp,%rbp
400484: b8 00 00 00 00 mov $0x0,%eax
400489: c9 leaveq
40048a: c3 retq
40048b: 90 nop
40048c: 90 nop
40048d: 90 nop
40048e: 90 nop
40048f: 90 nop

由此可见对于C语言是没有函数修饰的,所以C是不支持函数重载的!

extern “C”

有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译:

1
2
3
extern "C" int add(int a, char b) {
return 0;
}

如果是头文件与实现分离的情况下,只要头文件写了extern "C",源文件可写可不写,但是只要头文件没写extern "C" ,源文件中就不应该写extern "C",否则会报链接错误

函数重载与函数重写(覆写)的区别

方法重写(覆盖)override
发生在有继承关系的类中,子类定义了与父类完全相同的方法(方法名、返回值、参数列表全都一样),被重写的方法必须比父类中的方法权限更高!

缺省参数

缺省参数顾名思义,就是说参数列表中定义了默认的参数:

1
2
3
4
5
6
7
8
9
10
11
#include<iostream>

int fun(int a, int b = 10){ //定义缺省参数
return a+b;
}

int main(){
std::cout << fun(20) << std::endl; //30
std::cout << fun(20, 20) << std::endl; //40
return 0;
}

缺省参数的使用注意事项:
1、缺省参数必须定义在参数列表的最右边,这个比较容易理解,如果你把缺省参数定义在中间的话,编译器也就不知道到底哪些参数是缺省的
error: default argument missing for parameter 2 of ‘int fun(int, int)’

2、缺省参数不能同时在函数声明和定义中出现,只能二者留其一,这个也是比较好理解的,站在编译器的角度看问题,要想让编译器明白,首先我们自己的明白到底该用哪一个值作为默认值

3、缺省值必须是常量或者全局变量

4、C语言并不支持缺省参数

指针与引用

感谢金虎兄弟指出代码中的错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main(){

const int a = 10;
const int& b = a;

int c = 20;
const int& d = c;

const int x = 10;
//int& y = x; error 非const引用不能引用const变量

int e = 10;
//double& f = e; error
const double& f = e; //之所以可以这样定义,后面解释

return 0;
}

相同点

  1. 都是地址的概念
  2. 指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名

区别

  1. 指针是一个实体,而引用仅是个别名;

  2. 引用只能在定义时被初始化一次,之后不可变;指针可变;可以理解为引用从定义那一刻就已经不能被改变

  3. const的引用只能去引用const的变量,使用const引用非const变量是错误的,但是有一中情况除外:

    1
    2
    int e = 10;
    const double& f = e;

    这种情况是这样的,在计算机想把 int 转为 double 的时候会创建一个临时的double变量,而就在这个时引用便引用的是这块临时存储区域,所以没有报错,但是这样的一块临时区域本来是不应该被引用的!

  4. 引用不能为空,指针可以为NULL

  5. sizeof (引用) 得到的是所指向的变量(对象)的大小,而 sizeof 指针 得到的是指针本身(所指向的变量或对象的地址)的大小

  6. 指针和引用的自增(++)运算意义不一样,指针++是加上数据类型的大小,而引用++
    就是原变量加1,因为引用就是给原来的变量起别名!

引用的使用规则如下:

  • 引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
  • 不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
  • 一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)
  • 如果函数返回时,离开函数作用域后,其栈上空间已经还给系统,因此不能用栈上的空间作为引
    用类型返回。如果以引用类型返回,返回值的生命周期必须不受函数的限制(即比函数生命周期长)
赏

谢谢你请我喝咖啡

支付宝
微信
  • 本文作者: Tim
  • 本文链接: https://zouchanglin.cn/4007090141.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明出处!
  • C/C++
  • 编程语言

扫一扫,分享到微信

Linux常用命令
浅析指针与数组
  1. 1. 产生的过程
  • 函数重载
    1. 1. extern “C”
    2. 2. 函数重载与函数重写(覆写)的区别
  • 缺省参数
  • 指针与引用
    1. 1. 相同点
    2. 2. 区别
      1. 2.1. 引用的使用规则如下:
  • © 2017-2021 Tim
    本站总访问量次 | 本站访客数人
    • 所有文章
    • 工具

    tag:

    • 生活
    • Android
    • 索引
    • MySQL
    • 组件通信
    • Nginx
    • JavaSE
    • JUC
    • JavaWeb
    • 模板引擎
    • 前端
    • Linux
    • 计算机网络
    • Docker
    • C/C++
    • JVM
    • 上传下载
    • JavaEE
    • SpringCloud
    • Golang
    • Gradle
    • 网络安全
    • 非对称加密
    • IDEA
    • SpringBoot
    • Jenkins
    • 字符串
    • vim
    • 存储
    • 文件下载
    • Mac
    • Windows
    • NIO
    • RPC
    • 集群
    • 微服务
    • SSH
    • 配置中心
    • XML
    • Chrome
    • 压力测试
    • Git
    • 博客
    • 概率论
    • 排序算法
    • 分布式
    • 异常处理
    • 文件系统
    • 哈希
    • openCV
    • 栈
    • 回溯
    • SpringCore
    • 流媒体
    • rtmp
    • 面向对象
    • Vue
    • ElementUI
    • 软件工程
    • 异步
    • 自定义UI
    • ORM框架
    • 模块化
    • 交互式
    • Jsoup
    • Http Client
    • LRUCache
    • RabbitMQ
    • 消息通信
    • 服务解耦
    • 负载均衡
    • 权限
    • 多线程
    • 单例模式
    • Protobuf
    • 序列化
    • Python
    • m3u8
    • 堆
    • 二叉树
    • 自定义View
    • 观察者模式
    • 设计模式
    • 线程池
    • 动态扩容
    • 高可用
    • GC
    • ffmpeg
    • SpringMVC
    • REST
    • Redis
    • 缓存中间件
    • UML
    • Maven
    • Netty
    • 高性能网络
    • IPC通信
    • IO
    • Stream
    • 发布订阅
    • SQLite
    • Hash
    • 集合框架
    • 链表
    • Lambda
    • 汇编语言
    • 组件化
    • Router
    • 开发工具

      缺失模块。
      1、请确保node版本大于6.2
      2、在博客根目录(注意不是yilia-plus根目录)执行以下命令:
      npm i hexo-generator-json-content --save

      3、在根目录_config.yml里添加配置:

        jsonContent:
          meta: false
          pages: false
          posts:
            title: true
            date: true
            path: true
            text: false
            raw: false
            content: false
            slug: false
            updated: false
            comments: false
            link: false
            permalink: false
            excerpt: false
            categories: false
            tags: true
      

    • 思维导图
    • PDF工具
    • 无损放大
    • 代码转图
    • HTTPS证书