Fork me on GitHub

C++ 引用

10. 引用

  • References are a new data type in C++;
  • Local or global variables
    • For ordinary variables, the initial value is required
  • In parameter lists and member variables
    • Binding defined by caller or constructor
char c;         // a character
char* p = &c;   // a pointer to a character
char& r = c;    // a reference to a character

10.0 变量名回顾

  • 变量名实质上是一段连续存储空间的别名,是一个标号(门牌号);
  • 程序通过变量来申请并命名内存空间;
  • 通过变量的名字可以使用存储空间;

10.1 引用详解

  • 引用可以看作是已定义变量的别名
    • Declares a new name for an existing object
int X = 47;
int& Y = X;    // Y is a reference to X

// X and Y now refer to the same variable
cout << "Y = " << Y << endl;
Y = 18; // 此处,修改 Y 的值,也就是修改 X 的值
cout << "X = " << X << endl;
system("pause");

10.2 引用的规则

  • References must be initialized when defined
    • 普通引用在声明时,必须用其他的变量进行初始化;
    • 引用作为函数参数声明时,不需要初始化;
  • Initialization establishes a binding
// In declaration
int x = 3;
int& y = x;
const int& z = x;

// As a function argument
void f(int& x);
f(y);       // initialized when function is called

10.3 示例

引用的本质分析:

  • 引用在 C++ 的内部实现是一个常量指针
  • Type& name 等同于 Type* const name
#include <iostream>
using namespace std;

int* f(int* x) {
    (*x)++;
    return x;
}

int& g(int& x) {
    x++;
    return x;
}

int x;
int& h() {
    int q;
    return x;
}

int main() {
    int a = 0;
    f(&a);  // Ugly (but explicit)
    cout << "f(&a) = " << a << endl;
    g(a);   // Clean (but hidden)
    cout << "g(a) = " << a << endl;
    h() = 16;
    cout << "h() = " << x << endl;
}

10.3.1 示例2

#include <iostream>

using namespace std;

void myswap(int a, int b)
{
	int c;
	c = a;
	a = b;
	b = c;
}

void myswap01(int* a, int* b)
{
	int c;
	c = *a;
	*a = *b;
	*b = c;
}

void myswap02(int& a, int& b)
{
	int c = 0;
	c = a;
	a = b;
	b = c;
}

int main()
{
	int x, y;
	x = 10;
	y = 20;

	myswap(x, y);
	cout << "myswap  x:" << x << "\ty:" << y << endl;

	x = 10;
	y = 20;
	myswap01(&x, &y);
	cout << "myswap01  x:" << x << "\ty:" << y << endl;

	x = 10;
	y = 20;
	myswap02(x, y);
	cout << "myswap02  x:" << x << "\ty:" << y << endl;

	system("pause");
}

10.4 Pointers vs. References

  • Pointers

    • can be set to null
    • pointer is independent of existing objects
    • can change to point to a different address
  • References

    • can't be null
    • are dependent on an existing variable, they are an alias for an variable
    • can't change to a new "address" location
  • 约束

// No references to references

// No pointers to references
    int&* p;        // illegal

// Reference to pointer is ok
    void f(int*& p);    // ok

// No arrays of references

10.5 References as class members

  • Declared without initial value
  • Must be initialized using constructor initializer list
class X {
public:
    int& m_y;
    X(int& a);
};

X::X(int& a) : m_y(a) { }

10.6 Returning references

  • Functions can return references
    • But they better refer to non-local variables!
#include <assert.h>
const int SIZE = 32;
double myarray[SIZE];

double& subscript(const int i) {
    return myarray[i];
}
  • 当函数返回值为引用时
    • 若返回栈变量,则不能成为其他引用的初始值,不能作为左值使用;
    • 若返回静态变量或全局变量,可以成为其他引用的初始值,既可作为右值使用,也可作为左值使用;
  • 示例01:返回栈变量
#include "iostream"

using namespace std;

int getResult()
{
    int a;
    a = 10;
    return a;
}

int& getResult01()
{
    int a;  // 如果返回栈上的引用,有可能会有问题。
    a = 10;
    return a;
}

int* getResult02()
{
    int a;
    a = 10;
    return &a;
}

int main()
{
    int a1 = 0;
    int a2 = 0;

    a1 = getResult();
    cout << "a1: " << a1 << endl;

    a2 = getResult01();
    cout << "a2: " << a2 << endl;

    int &a3 = getResult01();
    cout << "a3: " << a3 << endl;

    getchar();
    return 0;
}
  • 示例02:返回静态变量
int& getResult05()
{
    static int a = 10;
    a++;
    return a;
}

int main()
{
    int a2 = getResult05();
    cout << "a2: " << a2 << endl;

    int &a3 = getResult05();
    cout << "a3: " << a3 << endl;

    getchar();
    return 0;
}
  • 示例03:函数返回值为引用,当左值
// g() 返回变量的值
int g()
{
    static int a = 10;
    a++;
    return a;
}

// g2() 返回变量本身,即返回变量所标识的内存空间
int& g2()
{
    static int a = 11;
    a++;
    cout << "g2() a:" << a << endl;
    return a;
}

int main()
{
    // 解释:g() 返回的结果为 10,下面的表达式等同于:10 = 100,故不成立
    // g() = 100;

    // 解释:g2() 返回的结果为 a,下面的表达式等同于:a = 100, 故成立
    g2() = 100; // 函数返回值为引用,当左值

    g2();   // 此时,结果输出 a: 101

    int c = g2();

    getchar();
    return 0;
}

10.7 const in Functions Arguments

  • Pass by const value -- don't do it
  • Passing by const reference: Person (const string& name, int weight);
    • don't change the string object
    • more efficient to pass by reference(address) than to pass by value(copy)
    • const qualifier protects from change

10.8 Temporary values are const

  • 示例:
#include <iostream>
using namespace std;

void f(cosnt int& i)
{
    cout << i << endl;
}

int main()
{
    int i = 3;
    f(i * 3);

    return 0;
}
  • 错误示例:
void func(int&);
func(i * 3);    // Generates error!

// 实际编译结果:
void func(int&);
const int temp@ = i * 3;
func(temp@);  // Problem -- binding const ref to non-const argument!

// The temporary is constant, since you can't access it.

10.9 const in Function returns

  • return by const value
    • For user defined types, it means "prevent use as an lvalue"
    • for built-in's it means nothing
  • return by const pointer or reference
    • depends on what you want your client to do with the return value

参考链接:

posted @ 2022-06-16 09:25  小a的软件思考  阅读(42)  评论(0编辑  收藏  举报