对比 C++ 和 Python,谈谈指针与引用 !

0 引言

指针(Pointer)是 C、C++ 以及 Java、Go 等语言的一个非常核心且重要的概念,而引用(Reference)是在指针的基础上构建出的一个同样重要的概念。

指针对于任何一个编程语言而言都是必须且重要的,虽然 Python 对指针这一概念进行了刻意的模糊与限制,但指针对于 Python 而言依然是一个必须进行深入讨论的话题。

本文基于 C++ 与 Python,讨论了 Python 中与指针及引用相关的一些行为。

 

 

 

Python资源共享群:484031800

 

1 什么是指针?为什么需要指针?

指针有两重含义:

(1)指代某种数据类型的指针类型,如整形指针类型、指针指针类型

(2)指代一类存放有内存地址的变量,即指针变量

指针的这两重含义是紧密联系的:作为一种变量,通过指针可以获取某个内存地址,从而为访问此地址上的值做好了准备;作为一种类型,其决定了内存地址的正确偏移长度,其应等于当前类型的单位内存大小。

如果一个指针缺少指针类型,即 void *,则显然,其虽然保存了内存地址,但这仅仅是一个起点地址,指针会因为无法获知从起点向后进行的偏移量,从而拒绝解指针操作;而如果一个指针缺少地址,即 nullptr,则其根本无法读取特定位置的内存。

指针存在的意义主要有以下几点:

  • 承载通过 malloc、new、allocator 等获取的动态内存
  • 使得 pass-by-pointer 成为可能

pass-by-pointer 的好处包括但不限于:

  • 避免对实参无意义的值拷贝,大幅提高效率
  • 使得对某个变量的修改能力不局限于变量自身的作用域
  • 使得 swap、移动构造函数、移动赋值运算等操作可以仅针对数据结构内部的指针进行操作,从而避免了对临时对象、移后源等对象的整体内存操作

由此可见,与指针相关的各操作对于编程而言都是必须的或十分重要的。

 

 

 

 

2 C++中的引用

在 C++ 中,引用具有与指针相似的性质,但更加隐形与严格。C++ 的引用分为以下两种:

2.1 左值引用

左值引用于其初始化阶段绑定到左值,且不存在重新绑定。

左值引用具有与被绑定左值几乎一样的性质,其唯一的区别在于 decltype 声明:

int numA = 0, &lrefA = numA;  // Binding an lvalue
cout << ++lrefA << endl;      // Use the lvalue reference as lvalue & rvalue
decltype(lrefA) numB = 1;     // Error!

左值引用常用于 pass-by-reference:

void swap(int &numA, int &numB)
{
    int tmpNum = numA;
    numA = numB;
    numB = tmpNum;
}
int main()
{
    int numA = 1, numB = 2;
    swap(numA, numB);
    cout << numA << endl << numB << endl;  // 2 1
}

2.2 右值引用

右值引用于其初始化阶段绑定到右值,其常用于移动构造函数和移动赋值操作。在这些场合中,移动构造函数和移动赋值操作通过右值引用接管被移动对象。

右值引用与本文内容无关,故这里不再详述。

3 Python中的引用

3.1 Python不存在引用

由上文讨论可知,虽然“引用”对于 Python 而言是一个非常常用的术语,但这显然是不准确的——由于 Python 不存在对左/右值的绑定操作,故不存在左值引用,更不存在右值引用。

3.2 Python的指针操作

不难发现,虽然 Python 没有引用,但其变量的行为和指针的行为具有高度的相似性,这主要体现在以下方面:

  • 在任何情况下(包括赋值、实参传递等)均不存在显式值拷贝,当此种情况发生时,只增加了一次引用计数
  • 变量可以进行重绑定(对应于一个不含顶层 const(top-level const)的指针)
  • 在某些情况下(下文将对此问题进行详细讨论),可通过函数实参修改原值

由此可见,Python变量更类似于(某种残缺的)指针变量,而不是引用变量。

 

 

 

 

3.2.1 构造函数返回指针

对于 Python 的描述,有一句非常常见的话:“一切皆对象”。

但在这句话中,有一个很重要的事实常常被人们忽略:对象是一个值,不是一个指针或引用。

所以,这句话的准确描述应该更正为:“一切皆(某种残缺的)指针”。虽然修改后的描述很抽象,但这是更准确的。

而由于对象从构造函数而来,至此我们可知:Python的构造函数将构造匿名对象,且返回此对象的一个指针。

这是 Python 与指针的第一个重要联系。

用代码描述,对于Python代码:

sampleNum = 0

 

其不类似于 C++ 代码:

int sampleNum = 0;

 

而更类似于:

int __tmpNum = 0, *sampleNum = &__tmpNum;
// 或者:
shared_ptr<int> sampleNum(new int(0));

3.2.2 __setitems__操作将隐式解指针

Python与指针的另一个重要联系在于 Python 的隐式解指针行为。

虽然 Python 不存在显式解指针操作,但(有且仅有)__setitems__操作将进行隐式解指针,通过此方法对变量进行修改等同于通过解指针操作修改变量原值。

此种性质意味着:

  1. 任何不涉及__setitems__的操作都将成为指针重绑定。

对于Python代码:

numList = [None] * 10
# Rebinding
numList = [None] * 5

其相当于:

int *numList = new int[10];
// Rebinding
delete[] numList;
numList = new int[5];
delete[] numList;

由此可见,对 numList 的非__setitems__操作,导致 numList 被绑定到了一个新指针上。

  1. 任何涉及__setitems__的操作都将成为解指针操作。

由于 Python 对哈希表的高度依赖,“涉及__setitems__的操作”在 Python 中实际上是一个非常广泛的行为,这主要包括:

  • 对数组的索引操作
  • 对哈希表的查找操作
  • 涉及__setattr__的操作(由于 Python 将 attribute 存储在哈希表中,所以__setattr__操作最终将是某种__setitems__操作)

我们用一个稍复杂的例子说明这一点:

对于以下Python代码:

class Complex(object):
    def __init__(self, real = 0., imag = 0.):
        self.real = real
        self.imag = imag
    def __repr__(self):
        return '(%.2f, %.2f)' % (self.real, self.imag)
def main():
    complexObj = Complex(1., 2.)
    complexObj.real += 1
    complexObj.imag += 1
    # (2.00, 3.00)
    print(complexObj)
if __name__ == '__main__':
    main()

 

 

 

 

 

其相当于:

class Complex
{
public:
    double real, imag;
    Complex(double _real = 0., double _imag = 0.): real(_real), imag(_imag) {}
};
ostream &operator<<(ostream &os, const Complex &complexObj)
{
    return os << "(" << complexObj.real << ", " << complexObj.imag << ")";
}
int main()
{
    Complex *complexObj = new Complex(1., 2.);
    complexObj->real++;
    complexObj->imag++;
    cout << *complexObj << endl;
    delete complexObj;
    return 0;
}

由此可见,无论是 int、float 这种简单的 Python 类型,还是我们自定义的类,其构造行为都类似使用 new 构造对象并返回指针。

且在 Python 中任何涉及“.”和“[]”的操作,都类似于对指针的“->”或“*”解指针操作。

<think>好的,我现在需要帮助用户了解C++的特点、用途及优势。首先,我得整理一下已有的信息。根据提供的引用内容,用户给出了四个引用,其中引用[1]提到C++功能强大、用途广泛,适合系统编程应用开发。引用[3]强调了学习C++的优势,比如待遇好语言本身的优势。引用[4]提到了一些资源,比如演化计算库,这可能说明C++在科学计算中的应用。不过用户的问题主要集中在特点、用途优势,所以需要围绕这三点展开。 首先,C++的特点。根据已知的知识,C++是面向对象的,支持多范式编程,包括过程化、面向对象、泛型编程等。同时,它具备高效性底层操作能力,允许内存管理指针操作。这些特点在引用[1][3]中都有所涉及,比如系统编程高效性。需要将这些点组织起来,分点说明。 然后是用途。C++常用于系统级开发,比如操作系统、驱动程序,游戏开发,嵌入式系统,高性能计算,金融领域等。引用[1]提到适合低级系统编程高级应用开发,所以需要具体举例,比如Windows内核、游戏引擎如Unreal Engine,以及高频交易系统等。引用[4]提到的演化计算库可能属于科学计算或优化算法领域,这也是一个用途点。 优势方面,性能高效、跨平台、生态丰富、兼容C语言等。引用[3]提到学习C++的优势,比如对底层硬件的控制,高性能,职业发展机会多。同时,引用[2]比较了C++Java,可能可以间接说明C++在性能控制力上的优势。 接下来要确保回答结构清晰,分点列出特点、用途、优势,并正确引用提供的资料。需要注意的是,用户提供的引用中有部分内容可能不直接相关,比如引用[2]是比较C++Java,但用户的问题没有提到比较,所以可能不需要深入这点,除非在优势中提到相对于其他语言的优势。 另外,用户要求使用中文,数学公式用$...$,独立公式用$$...$$,但当前问题似乎不涉及数学公式,可能不需要处理这部分。但需要检查是否有地方需要用到,比如在解释性能时提到时间复杂度等,但暂时看来不需要。 最后,生成相关问题。需要根据回答内容提出相关问题,比如性能优化的方法,应用场景的具体例子,其他语言的比较,学习资源推荐等。需要参考用户提供的示例中的相关问题结构,确保问题内容相关且有意义。 现在需要组织语言,确保每个部分都有引用支持。例如,在特点中提到的多范式编程可以引用[1],高效性引用[1][3],用途中的系统编程引用[1],游戏开发可能来自常识,但如果没有引用支持可能需要调整。不过用户提供的引用中没有直接提到游戏开发,所以可能需要用更一般的应用场景,或者依赖引用[1]中的“各种应用程序”来涵盖。 总结下来,回答的结构应该是: 1. C++的特点 - 多范式编程(面向对象、泛型等) - 高效性底层控制(指针、内存管理) - 可移植性(跨平台) - 丰富的标准库生态 2. 主要用途 - 系统级编程(操作系统、驱动) - 游戏开发 - 嵌入式系统 - 高性能计算 - 金融领域 3. 核心优势 - 性能优势 - 硬件级控制 - 跨平台兼容性 - 兼容C语言 - 职业发展机会 在写作过程中,每个部分末尾需要添加引用,例如在特点中的多范式部分引用[1],高效性引用[1][3]等。确保每个引用自然衔接,不重复使用。 最后生成的相关问题可能需要包括:如何优化C++程序性能?C++在嵌入式开发中的应用案例?C++Java的主要区别?学习C++的推荐资源?这些都需要基于回答内容,同时参考用户提供的引用,比如引用[2]比较了C++Java,可以作为问题之一。引用[4]提到资源汇总,可以生成相关问题。</think>### C++ 编程语言的特点、用途及优势 #### 一、特点 1. **多范式编程** C++ 支持面向对象、泛型、过程化等多种编程范式,开发者可根据需求灵活选择。例如,泛型编程通过模板实现,可编写高度复用的代码[^1]。 2. **高效性底层控制** 允许直接操作内存硬件资源(如指针),适合对性能要求高的场景[^3]。 3. **可移植性** 代码可在多种平台(Windows、Linux、嵌入式系统等)编译运行,仅需少量修改。 4. **丰富的标准库生态** 标准库提供容器、算法等工具,第三方库(如 Boost、Evolving Objects)扩展了科学计算、机器学习等领域的支持[^4]。 #### 二、主要用途 1. **系统级编程** 开发操作系统(如 Windows 内核)、驱动程序等底层软件。 2. **游戏图形引擎** 高性能特性使其成为游戏引擎(如 Unreal Engine)的首选语言。 3. **嵌入式系统** 适用于资源受限的嵌入式设备开发(如物联网设备)。 4. **高性能计算** 用于科学模拟、金融高频交易等需要实时处理的场景。 5. **跨平台应用** 开发桌面软件(如 Adobe 系列)服务器程序。 #### 三、核心优势 1. **性能卓越** 编译型语言直接生成机器码,运行效率接近 C 语言,远高于 Java、Python 等[^3]。 2. **硬件级控制** 通过指针内存管理实现精细资源控制,适合开发系统软件[^1][^3]。 3. **兼容 C 语言** 可直接调用 C 语言代码,复用现有生态[^1]。 4. **职业竞争力** 掌握 C++ 在游戏开发、高频交易等领域具有显著职业优势[^3]。 ```cpp // 示例:C++ 的面向对象特性 #include <iostream> using namespace std; class Rectangle { private: int width, height; public: Rectangle(int w, int h) : width(w), height(h) {} int area() { return width * height; } }; int main() { Rectangle rect(3, 4); cout << "Area: " << rect.area() << endl; // 输出:Area: 12 return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值