举例剖析C++中引用的本质及引用作函数参数的使用_C 语言

引用的意义与本质
1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2)引用相对于指针来说具有更好的可读性和实用性

引用本质思考:
思考、C++编译器背后做了什么工作?

#include <iostream>
using namespace std; 

int main()
{
  int a = 10;
  // 单独定义的引用时,必须初始化;说明很像一个常量
  int &b = a;
  // b是a的别名
  b = 11;
  cout << "b--->" << a << endl;
  printf("a:%d\n", a);
  printf("b:%d\n", b);
  printf("&a:%d\n", &a);
  printf("&b:%d\n", &b);
  system("pause");
  return 0;
} 

引用是一个有地址,引用是常量。

char *const p

引用的本质:
1)引用在C++中的内部实现是一个常指针
Type& name <--> Type*const name
2)C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。
3)从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏

间接赋值成立的三个条件:
1定义两个变量(一个实参一个形参)
2建立关联实参取地址传给形参
3*p形参去间接的修改实参的值

引用在实现上,只不过是把:间接赋值成立的三个条件的后两步和二为一。
当实参传给形参引用的时候,只不过是c++编译器帮我们程序员手工取了一个实参地址,传给了形参引用(常量指针)。

引用做函数参数

普通引用在声明时必须用其它的变量进行初始化,
引用作为函数参数声明时不进行初始化

//复杂数据类型的引用
#include <iostream>
using namespace std; 

struct Teacher
{
  char name[64];
  int age;
}; 

void printfT(Teacher *pT)
{
  cout << pT->age << endl;
} 

//pT是t1的别名 ,相当于修改了t1
void printfT2(Teacher &pT)
{
  //cout<<pT.age<<endl;
  pT.age = 33;
} 

//pT和t1的是两个不同的变量
void printfT3(Teacher pT)
{
  cout << pT.age << endl;
  pT.age = 45; //只会修改pT变量 ,不会修改t1变量
}
void main()
{
  Teacher t1;
  t1.age = 35; 

  printfT(&t1); 

  printfT2(t1); //pT是t1的别名
  printf("t1.age:%d \n", t1.age); //33 

  printfT3(t1);// pT是形参 ,t1 copy一份数据 给pT   //---> pT = t1
  printf("t1.age:%d \n", t1.age); //35 

  cout << "hello..." << endl;
  system("pause");
  return;
} 

引用的难点:函数返回值是引用(引用当左值)
当函数返回值为引用时,若返回栈变量,不能成为其它引用的初始值,不能作为左值使用;
若返回静态变量或全局变量,可以成为其他引用的初始值,即可作为右值使用,也可作为左值使用。
C++链式编程中,经常用到引用。

#include <iostream>
using namespace std;
//返回值是基础类型,当引用
int getAA1()
{
  int a;
  a = 10;
  return a;
} 

//基础类型a返回的时候,也会有一个副本
int& getAA2()
{
  int a; // 如果返回栈上的引用,有可能会有问题
  a = 10;
  return a;
} 

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

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

  a1 = getAA1();
  a2 = getAA2(); // a是10
  int &a3 = getAA2(); // 若返回栈变量,不能成为其他引用的初始值
  cout << a1 << endl;
  cout << a2 << endl;
  cout << a3 << endl; // a3是乱码,这里出现了问题
  // 编译器看到a3是个引用,自动进行对a3的地址进行取值
  // 但是函数getAA2退出的时候已经释放了这个地址的内存,所以这里是乱码 

  return 0;
} 

返回值是static变量,当引用

//static修饰变量的时候,变量是一个状态变量
int j()
{
  static int a = 10;
  a++;
  printf("a:%d \n", a);
  return a; 

} 

int& j1()
{
  static int a = 10;
  a++;
  printf("a:%d \n", a);
  return a;
} 

int *j2()
{
  static int a = 10;
  a++;
  printf("a:%d \n", a);
  return &a;
} 

void main()
{
  // j()的运算结果是一个数值,没有内存地址,不能当左值
  //11 = 100;
  //*(a>b?&a:&b) = 111;
  //当被调用的函数当左值的时候,必须返回一个引用
  j1() = 100; //编译器帮我们打造了环境
  j1();
  *(j2()) = 200; //相当于手工的打造,做左值的条件
  j2();
  system("pause");
} 

返回值是形参,当引用

int g1(int *p)
{
  *p = 100;
  return *p;
} 

int& g2(int *p) //
{
  *p = 100;
  return *p;
} 

//当使用引用语法的时候 ,不去关心编译器引用是怎么做的
//当分析乱码这种现象的时候,才去考虑c++编译器是怎么做的。。。。
void main()
{
  int a1 = 10;
  a1 = g2(&a1); 

  int &a2 = g2(&a1); //用引用去接受函数的返回值,是不是乱码,关键是看返回的内存空间是不是被编译器回收了。。。。
  printf("a1:%d \n", a1);
  printf("a2:%d \n", a2); 

  system("pause");
} 

 

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c++
, 引用
函数参数
c语言深度剖析、剖析式的语言的特点是、c语言深度剖析 第二版、c语言深度剖析 pdf、电子文献引用举例,以便于您获取更多的相关知识。

时间: 2024-08-29 17:26:39

举例剖析C++中引用的本质及引用作函数参数的使用_C 语言的相关文章

剖析C++编程当中指针作为函数参数的用法_C 语言

在C语言中,函数指针变量常见的用途之一是作为函数的参数,将函数名传给其他函数的形参.这样就可以在调用一个函数的过程中根据给定的不同实参调用不同的函数. 例如,利用这种方法可以编写一个求定积分的通用函数,用它分别求5个函数的定积分: 可以看出,每次需要求定积分的函数是不一样的.可以编写一个求定积分的通用函数integral,它有3个形参: 下限a.上限b,以及指向函数的指针变量fun.函数原型可写为: double integral (double a, double b, double (*fu

剖析C++编程中friend关键字所修饰的友元函数和友元类_C 语言

在某些情况下,为不是类成员的函数或单独类中的所有函数授予成员级别的访问权会更方便.仅类实现器可以声明其友元.函数或类不能将其自身声明为任何类的友元.在类声明中,使用 friend 关键字和非成员函数名称或其他类,以允许其访问你的类的专用和受保护成员.语法 friend class-name; friend function-declarator; 友元声明如果声明以前未声明的友元函数,则该函数将被导出到封闭非类范围. 友元声明中声明的函数被视为已使用 extern 关键字声明.(有关 exter

详解C++编程中向函数传递引用参数的用法_C 语言

引用类型的函数参数向函数传递引用而非大型对象的效率通常更高. 这使编译器能够在保持已用于访问对象的语法的同时传递对象的地址. 请考虑以下使用了 Date 结构的示例: // reference_type_function_arguments.cpp struct Date { short DayOfWeek; short Month; short Day; short Year; }; // Create a Julian date of the form DDDYYYY // from a G

C++中异常处理的基本思想及throw语句抛出异常的使用_C 语言

异常处理基本思想C++的异常处理的基本思想大致可以概括为传统错误处理机制.通过函数返回值来处理错误. 1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理.上层调用者可以再适当的位置设计对不同类型异常的处理. 2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图 3)异常超脱

C++中函数的用法小结_C 语言

函数在C++中的使用,无非2种地方,一处是函数的定义,一处是函数的调用.而函数的定义则非常简单,由三个部分组成:函数的返回类型.函数名和函数的形参表.当然,这里不同的函数定义可以还会稍有不同,比如类的成员函数.内联函数等.这里我们主要讨论函数的调用时需要注意的一些问题. 一.参数传递 我们将函数定义或声明里的参数叫形参,而在调用函数时传入的参数叫实参.那么根据形参类型的不同,有几下形式的参数传递. 1,非引用形参 1)普通的内置类型 普通非引用类型的参数通过复制对应的实参实现形参的初始化.当用实

详解C++中的函数调用和下标以及成员访问运算符的重载_C 语言

函数调用使用括号调用的函数调用运算符是二元运算符. 语法 primary-expression ( expression-list ) 备注 在此上下文中,primary-expression 为第一个操作数,并且 expression-list(可能为参数的空列表)为第二个操作数.函数调用运算符用于需要大量参数的操作.这之所以有效,是因为 expression-list 是列表而非单一操作数.函数调用运算符必须是非静态成员函数. 函数调用运算符在重载时不会修改函数的调用方式:相反,它会在运算符

深度探究C++中的函数重载的用法_C 语言

C++ 允许同一范围内具有相同名称的多个函数的规范.这些函数称为重载函数,"重载"中对其进行了详细介绍.利用重载函数,程序员可以根据参数的类型和数量为函数提供不同的语义. 例如,采用字符串(或 char *)参数的 print 函数执行的任务与采用"双精度"类型的参数的函数执行的任务截然不同.重载允许通用命名并使程序员无需创建名称,例如 print_sz 或 print_d.下表显示了 C++ 使用函数声明的哪些部分来区分同一范围内具有相同名称的函数组.重载注意事项

C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结_C 语言

前言 这篇文章总结的是C++中的类型转换,这些小的知识点,有的时候,自己不是很注意,但是在实际开发中确实经常使用的.俗话说的好,不懂自己写的代码的程序员,不是好的程序员:如果一个程序员对于自己写的代码都不懂,只是知道一昧的的去使用,终有一天,你会迷失你自己的. C++中的类型转换分为两种: 1.隐式类型转换: 2.显式类型转换. 而对于隐式变换,就是标准的转换,在很多时候,不经意间就发生了,比如int类型和float类型相加时,int类型就会被隐式的转换位float类型,然后再进行相加运算.而关

详解C++中的vector容器及用迭代器访问vector的方法_C 语言

vector vector是相同类型对象的集合.集合中的每个对象有个对应的索引.vector常被称为容器(container). 为了使用vector,需要: #include <vector> using std::vector; vector是一个类模版(class template).C++有函数模版和类模版.模版本身不是函数或类,必须通过指定 类型让编译器去实例化(instantiation)它.比如vector<int> ivec. vector是模版,不是类型.从vec