高级引用和指针开发指南
立即解锁
发布时间: 2025-08-17 01:59:00 阅读量: 1 订阅数: 4 

# 高级引用和指针开发指南
## 1. 学习目标
在本文中,我们将学习以下内容:
- 如何使用引用传递使程序更高效
- 何时使用引用,何时使用指针
- 如何避免使用指针时的内存问题
- 如何避免使用引用时的陷阱
## 2. 引用传递以提高效率
### 2.1 值传递的代价
每次通过值将对象传递给函数时,都会创建该对象的一个副本。每次通过值从函数返回对象时,又会创建另一个副本。对于大型的用户自定义对象,这些副本的创建成本很高,会消耗更多的内存,并且程序运行速度会变慢。用户自定义对象在栈上的大小是其每个成员变量大小的总和,而这些成员变量本身又可能是用户自定义对象。通过将这样的大型结构复制到栈上来传递,在性能和内存消耗方面的代价都很大。
此外,每次创建临时副本时,编译器会调用特殊的构造函数——复制构造函数。当临时对象被销毁(即函数返回时),会调用对象的析构函数。如果通过值返回对象,还必须创建并销毁该对象的副本。对于大型对象,这些构造函数和析构函数的调用在速度和内存使用方面的代价都很高。
### 2.2 示例代码 ObjectRef.cpp
以下是 `ObjectRef.cpp` 的完整代码:
```cpp
#include <iostream>
class SimpleCat
{
public:
SimpleCat(); // constructor
SimpleCat(SimpleCat&); // copy constructor
~SimpleCat(); // destructor
};
SimpleCat::SimpleCat()
{
std::cout << "Simple Cat Constructor ..." << std::endl;
}
SimpleCat::SimpleCat(SimpleCat&)
{
std::cout << "Simple Cat Copy Constructor ..." << std::endl;
}
SimpleCat::~SimpleCat()
{
std::cout << "Simple Cat Destructor ..." << std::endl;
}
SimpleCat FunctionOne(SimpleCat theCat);
SimpleCat* FunctionTwo(SimpleCat *theCat);
int main()
{
std::cout << "Making a cat ..." << std::endl;
SimpleCat Frisky;
std::cout << "Calling FunctionOne ..." << std::endl;
FunctionOne(Frisky);
std::cout << "Calling FunctionTwo ..." << std::endl;
FunctionTwo(&Frisky);
return 0;
}
// FunctionOne, passes by value
SimpleCat FunctionOne(SimpleCat theCat)
{
std::cout << "Function One. Returning ..." << std::endl;
return theCat;
}
// functionTwo, passes by reference
SimpleCat* FunctionTwo (SimpleCat *theCat)
{
std::cout << "Function Two. Returning ..." << std::endl;
return theCat;
}
```
### 2.3 代码运行结果分析
运行该程序时,输出如下:
```
Making a cat ...
Simple Cat Constructor ...
Calling FunctionOne ...
Simple Cat Copy Constructor ...
Function One. Returning ...
Simple Cat Copy Constructor ...
Simple Cat Destructor ...
Simple Cat Destructor ...
Calling FunctionTwo ...
Function Two. Returning ...
Simple Cat Destructor ...
```
代码中,`SimpleCat` 类的构造函数、复制构造函数和析构函数都会输出信息,方便我们观察它们的调用情况。在 `main` 函数中,首先创建了一个 `SimpleCat` 对象 `Frisky`,这会调用构造函数。然后调用 `FunctionOne`,由于是通过值传递对象,会创建对象的副本,调用复制构造函数。函数返回时,又会创建一个副本,再次调用复制构造函数。返回值未被赋值给任何对象,临时对象被销毁,调用析构函数。函数结束后,其局部副本超出作用域,也会被销毁,再次调用析构函数。
而调用 `FunctionTwo` 时,通过引用传递参数,不会创建副本,因此不会调用复制构造函数和析构函数。
### 2.4 引用传递的优缺点
引用传递避免了创建副本和调用复制构造函数,因此通常更高效。但它也会传递对象本身,从而使对象在被调用的函数中可能被修改。
## 3. 传递 const 指针
### 3.1 普通指针传递的风险
虽然将指针传递给 `FunctionTwo` 更高效,但存在危险。`FunctionTwo` 不应该修改传递给它的 `SimpleCat` 对象,但它得到了对象的地址,这使得对象可能被意外修改,从而破坏了值传递所提供的保护。
### 3.2 传递 const 指针的解决方案
如果想同时获得值传递的安全性和引用传递的效率,可以传递一个指向 `SimpleCat` 的 `const` 指针。这样可以防止调用 `SimpleCat` 的任何非 `const` 成员函数,从而保护对象不被修改。
### 3.3 示例代码 ConstPasser.cpp
以下是 `ConstPasser.cpp` 的完整代码:
```cpp
#include <iostream>
class SimpleCat
{
public:
SimpleCat();
SimpleCat(SimpleCat&);
~SimpleCat();
int GetAge() const { return itsAge; }
void SetAge(int age) { itsAge = age; }
private:
int itsAge;
};
SimpleCat::SimpleCat()
{
std::cout << "Simple Cat Constructor ..." << std::endl;
itsAge = 1;
}
SimpleCat::SimpleCat(SimpleCat&)
{
std::cout << "Simple Cat Copy Constructor ..." << std::endl;
}
SimpleCat::~SimpleCat()
{
std::cout << "Simple Cat Destructor ..." << std::endl;
}
const SimpleCat * const
FunctionTwo (const SimpleCat *const theCat);
int main()
{
std::cout << "Making a cat ..." << std::endl;
SimpleCat Frisky;
std::cout << "Frisky is ";
std::cout << Frisky.GetAge() << " years old" << std::endl;
int age = 5;
Frisky.SetAge(age);
std::cout << "Frisky is ";
std::cout << Frisky.GetAge() << " years old" << std::endl;
std::cout << "Calling FunctionTwo ..." << std::endl;
FunctionTwo(&Frisky);
std::cout << "Frisky is ";
std::cout << Frisky.GetAge() << " years old" << std::endl;
return 0;
}
// functionTwo, passes a const pointer
const SimpleCat * const
FunctionTwo (const SimpleCat * const theCat)
{
std::cout << "Function Two. Returning ..." << std::endl;
std::cout << "Frisky is now " << theCat->GetAge();
std::cout << " years old \n";
// theCat->SetAge(8); const!
return theCat;
}
```
### 3.4 代码运行结果分析
运行该程序时,输出如下:
```
Making a cat ...
Simple Cat Constructor ...
Frisky is 1 years old
Frisky is 5 years old
Calling FunctionTwo ...
Function Two. Returning ...
Frisky is now 5 years old
Frisky is 5 years old
Simple Cat Destructor ...
```
在这个程序中,`SimpleCat` 类添加了 `GetAge()` 和 `SetAge()` 两个访问器函数,其中 `GetAge()` 是 `const` 函数,`SetAge()` 不是。`FunctionTwo` 的参数和返回值现在被声明为指向常量对象的常量指针。由于仍然通过引用传递参数和返回值,不会创建副本,因此不会调用复制构造函数。而且,由于指针是常量,不能调用非 `const` 成员函数 `SetAge()`。
## 4. 引用作为指针的替代方案
### 4.1 引用传递的优势
`ConstPasser` 程序解决了创建额外副本的问题,节省了复制构造函数和析构函数的调用。但使用指针仍然有些繁琐。因为我们知道参数永远不会为 `NULL`,所以传递引用比传递指针更方便。
### 4.2 示例代码 RefPasser.cpp
以下是 `RefPasser.cpp` 的完整代码:
```cpp
#include <iostream>
class SimpleCat
{
public:
SimpleCat();
SimpleCat(SimpleCat&);
~SimpleCat();
int GetAge() const { return itsAge; }
void SetAge(int age) { itsAge = age; }
private:
int itsAge;
};
SimpleCat::SimpleCat()
{
std::cout << "Simple Cat Constructor ..." << std::endl;
itsAge = 1;
}
SimpleCat::SimpleCat(SimpleCat
```
0
0
复制全文
相关推荐










