首页 > 编程语言 >C++指针与引用(Pointers OR References)

C++指针与引用(Pointers OR References)

时间:2024-05-01 10:22:24浏览次数:23  
标签:cout reference int Pointers C++ 指向 References pointer 指针

一、Pointers

  Pointer是指针,可以用来指向任何一个objects,包括一般变量:

1 int  i = 3;
2 int * pi = &i;
3 cout << pi << endl; // 0x0064FDF0
4 cout << *pi << endl; // 3

  此时pi本身内含i的地址,要取出pi所指向的object,可以使用*运算符(dereference operator).Pointer也可以用来指向任何一个class type objects。由于下面的pPoint指向一整个大结构(一个object),如果要取用其中的members(data members 或member functions都可以,只要他们的封装等级是public),必须使用—>运算符(arrow operator),例如:

1 class CPoint { public: float _x, _y, _z; };
2 CPoint  * pPoint = new CPoint;
3 cout << pPoint << endl; // 0x00770560
4 pPoint->_x = 9.28;
5 cout << pPoint->_x << endl; // 9.28

  Pointer 甚至可以指向一个不明对象(void):

1 void * pv;
2 pv = malloc(1024); // 配置 1024 bytes(来自 heap)
3 cout << pv << endl; // 0x00760A14

  此时如果要提取 pv 所指的对象,不可以,会出现编译出错:

1 cout << *pv << endl; // error C2100: illegal indirection

  也说是说,pointer本身没有意义,它的意义来自于它的类型,因此,将pointer前进一个单位,究竟是前进多少个bytes呢?那要看pointer的类型,如果将int *pi和CPoint *pPoint各加1,得到:

1 cout << ++pi << endl; // 0x0064FDF4,比原先增加 4
2 cout << ++pPoint << endl; // 0x0077056C,比原先增加 12

  这是因为在32位的系统中int为4 bytes,而我们设计的CPoint里面有一个float数据,大小为12bytes,所以各指针累加1时,分别前进4bytes和12bytes。如果把一个指向不明对象的指针加1,会得到什么结果呢?不会有结果,只会编译出错:

1 cout << ++pv << endl; // error C2036: 'void *' : unknown size

  当然,如果你做了强转型(cast)动作,就可以解决“不明对象”的问题,因为你赋予了该指针一个明确的类型,例如:

1 double * pd = (double*)pv; // 强转型。double is 8 bytes.
2 cout << pd << endl; // 0x00760A14
3 cout << ++pd << endl; // 0x00760A1C,比原先增加 8

  下表是上述验证结果的一个整理:

   当我们开始设计classes继承体系,有许多时候需要把一个pointer指向一个类型不符的object(但彼此类型又有继承的关系存在,这其实正是polymorphism的一个精髓),这时候类型的转换就非常重要。强制转型太过粗暴,在不够安全的时候仍然强转换,存在风险。C++有其它更精致的转型工具,我们后续再谈。

  Pointer不但可以指向object,还可以指向class的data members或member functions。它们的形式有点怪,结果也可能出人意外,这些问题我们后续再谈。

二、References

  与pointer常常相提并论,并且常常被混淆不清的是所谓的reference。Reference(&)像是一个常数指针,可以被自动提取(dereference)。下面这个例子就是使r成为x的一个reference:

1 int x;
2 int& r = x; // r is a reference of x

  当一个refernce产生,它必须被初始化为某个原已存在的object,像上面那样,如查我写:

1 int& q = 12;

  那么编译器会先配置一块int内存空间,将内容设为12,然后把q这个reference“捆绑”到该空间上。重点是,任何reference都必须被“捆绑”到某一个空间,成为一个"化身“。当你处理该reference,你就是在处理那个被捆绑的空间。如果:

1 int x = 0;
2 int& r = x; // r is a reference of x
3 int* p = &x; // p is a pointer to x
4 r++; // 请注意:sizeof(r) == sizeof(x)

  那么r和x的现值都为1,因为增加r的值就是增加x 的值。

   面对reference,最简单的想像就是,把它幻想为一个形式漂亮的pointer。这个形式漂亮的pointer好处是,我们不需要担心它是否被初始化(编译器会强迫做),也需要担心何提取(dereference)它(同样的,编译器会负责)。Refernce虽然在本质上是一个指针,在形式却是个object。也就是因为其形式漂亮,而本质实用(用于call by refernce),所以refernce常被用于函数的参数列表(arguments list)和回传值(return value)。下面就是个例子:

  

 1 int* funcl(int* x)
 2 {
 3     (*x)++;
 4     return x;
 5 }
 6 
 7 int& func2(int& x)
 8 {
 9     x++;
10     return x;
11 }
12 
13 int main()
14 {
15    int a=0;
16    //ugly but explictit,你可以你可以清楚看到传給 func1() 的是个指针。
17    //传回值的形式也很「难看」。
18    cout<<*funcl(&a)<<endl;
19    // clean but hidden。传給 func2() 的其实是个指针(借助 reference)。
20    // 但你看不出來。传回的也是指针(借助 reference),你也看不出來。
21    cout<<func2(a)<<endl;
22    23     return 0;
24 }

 

标签:cout,reference,int,Pointers,C++,指向,References,pointer,指针
From: https://www.cnblogs.com/ruanchunyi/p/18169059

相关文章

  • C/C++如何写调试宏
    1.调试宏以及测试在写代码时,不可避免需要打印提示、警告、错误等信息,且要灵活控制打印信息的级别。另外,还有可能需要使用宏来控制代码段(主要是调试代码段)是否执行。为此,本文提供一种调试宏定义方案,包括打印字符串信息LOG1宏和格式化打印LOG2宏,且能通过宏控制代码段执行。完整代......
  • 《Effective C++》第三版-3. 资源管理(Resource Management)
    目录条款13:以对象管理资源(Useobjectstomanageresources)关键想法智能指针条款14:在资源管理类中小心copying行为(Thinkcarefullyaboutcopyingbehaviorinresource-managingclasses)条款15:在资源管理类中替工对原始资源的访问(Provideaccesstorawresourcesinresource-ma......
  • 学习 C++,从搭建 Visual Studio Code 开始
    0.声明本文针对Windows和Linux系统配置VisualStudioCode,Mac贵族请勿入内。本文以Windows10系统演示。1.准备工作1.1.安装VisualStudioCodeWindows:官网下载链接选择Windows(Windows10,11)进行安装Linux:在应用商店搜索VisualStudioCode,安装即......
  • C/C++、Java 与 Python 中未初始化变量的处理比较
    在C/C++中,未初始化的变量的值是不确定的,可能是随机的。 在Python中,如果直接使用未初始化的变量,会引发NameError异常。Python要求变量在使用前必须进行赋值或初始化。 而在Java中,直接使用未初始化的局部变量会导致编译错误,必须先对变量进行初始化。 C++和Java在字......
  • 一文详解C++的vector
    vector是C++中使用频率最高的标准库,可以在程序运行时动态改变其大小(例如添加或删除元素),因此又被称为动态数组。使用时,用户无需在意底层内存管理的细节,因为它已经帮你做了这件事情。使用前需要导入<vector>头文件,以下是vector的常见用法:1.创建vectorvector用于保存一组同类型的......
  • 浅析OpenCV分水岭变换watershed函数的markers参数[C++]
    0.前言本文是笔者在学习C++OpenCV库时学习心得,在学习分水岭变换函数时,由于缺少相关学习资料,导致笔者理解吃力,故写此文章阐述一下对该函数的理解,希望对其他学习人士提供帮助。本文主要介绍了watershed函数参数以及参数实际表示。请您按文章次序阅读。您需要提前了解的相关知......
  • 在Linux系统下用命令行编译调试C++
    在Linux系统下用命令行编译调试C++目录在Linux系统下用命令行编译调试C++一、编译1.单文件编译2.多文件编译3.链接第三方动态库二、调试1.启动和退出2.查看源代码:list/l3.断点:breakpoint/br、watchpoint4.单步、步入、跳出5.计算表达式命令:expression/expr、p、po6.操作......
  • C++ 学习笔记
    ​1、基础概念C++是一种高性能的编程语言,由BjarneStroustrup在1980年代初设计,旨在为C语言添加面向对象的功能。自那时起,C++已发展成为一种支持过程性、面向对象和泛型编程的多范式语言,广泛应用于系统软件、游戏开发、驱动程序、嵌入式固件等领域。要开始使用C++,首先需要......
  • 深入理解 C++ 中的多态与文件操作
    C++多态多态(Polymorphism)是面向对象编程(OOP)的核心概念之一,它允许对象在相同操作下表现出不同的行为。在C++中,多态通常通过继承和虚函数来实现。理解多态想象一个场景,你有一个动物园,里面有各种动物,如猫、狗、鸟等。每个动物都有自己的叫声。使用面向对象编程,我们可以创建一个......
  • C++里也有菱形运算符?
    最近在翻《c++函数式编程》的时候看到有一小节在说c++14新增了“菱形运算符”。我寻思c++里好像没什么运算符叫这名字啊,而且c++14新增的功能很少,我也不记得有添加这种语法特性。一瞬间我有些怀疑我的记忆了,所以为了查漏补缺,我写了这篇文章。什么是菱形运算符这个概念在Java里比......