引用&&指针&&返回值&&定义声明&&生命周期&&const

1. 首先了解一下声明和定义的区别:

?    声明,其实就是描述一个元素是有什么构成的;
?    定义,其实就是在内存中划分出一个区域且用符号关联起来;
?    变量和对象不加extern永远是定义,类中的除外。 函数只有函数头是声明,有函数体的是定义。 类永远只是声明。类成员函数的函数体是定义。
?    函数的声明和定义的不同点在于函数的声明不包含函数体,仅仅是fact();

2. 其次了解一下局部对象的生命周期

?    局部变量
i.    形参和函数体内定义的变量统称局部变量
ii.    局部变量转换成为全局变量,则使用static关键字就能实现;
iii.    局部变量的生存周期,在函数调用时被创建,在函数结束的时候就销毁,例:形参
iv.    有两种方式可以将函数体内值得改变传回主函数,一种是将形参设置为引用的形参,其实是实参和形参绑定在一块儿,因而值可以回传,另外一种是通过指针形参,改变实参传递过来地址的值,去改变函数体内的值。

3. 引用

A.    可能出现的错误情况:
Int  ival =1024;
Int  &refVal;  //引用必须进行初始化,
改正: int &refVal = ival;
//因为无法令引用重新绑定到另外一个对象,因此引用必须进行初始化;
引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字;
B.    情况2:
Int  &refVal1 =10; // 错误:引用类型的初始值必须是一个对象,不能是字面值;
double dval = 3.14;
int &refVal =dval; //错误,此处引用类型的初始值必须是int类型的对象;
C.    总结: 引用初始值必须是一个对象,不能是字面值;引用必须进行初始化;引用类型和绑定的类型必须一致。切记,哪怕类型之间可以相互转换,也不可以,必须类型一致;

4. const &

A.    const 用法
i.    定义一种变量,它的值不能被改变。
ii.    好处:用一个变量来表示缓冲区的大小,使用变量的好处是当我们觉得缓冲区大小不再合适时,很容易对其进行调整,但是我们又要随时警惕防止程序一不小心改变这个值。因而用const
iii.    const 必须进行初始化;
iv.    引用的好处:避免拷贝,可以直接比较;使用引用形参返回额外信息,主要是为了改善一个函数只能返回一个值得情况,这样函数可以返回多值。
v.    补充:顶层const是指指针本身是个常量,指针所指的内容是可以改变的,当形参有顶层const时,顶层const可以忽略掉,传给他常量对象或者非常量对象都是可以的,因为传入形参的本身就是局部变量,不会改变实参的值。
vi.    数组引用形参
B.    总结:
常量引用也必须进行初始化,并且不能通过该对象别名去修改已知非常量的值,绑定的值可以是常量也可以是非量,和引用有一点不同
double dval = 3.14; const int &ri =dval;//当类型不同时,转换时可以进行的.
//常量引用的好处之一避免拷贝对象~bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}//避免拷贝对象

//常量引用的好处之二___可以使函数返回多个值

//返回s中c第一次出现的位置索引
//引用形参occurs负责统计c出现的总次数

string::size_type find_char(const string &s, char c, string::size_type &occurs)
{
auto ret = s.size(); //第一次出现的位置
occurs = 0;
for (decltype(ret) i = 0; i != s.size(); ++i)
{
if (s[i] == c)
{
if (ret == s.size())
ret = i; //记录c第一次出现的位置
++occurs;//将出现的次数+1
}
}
return ret; //出现次数通过occurs隐式传回
}

int main()
{
string s = { "Hello world, welcome to beijing !" };
decltype(s.size()) ctr = 0;
auto index = find_char(s, ‘o‘, ctr);
cout << "string S has " << ctr << " times o" << endl;
}

5. 返回值为&

A.    关于返回值是如何返回的:返回的值用于初始化调用点的一个临时量,该临时两就是函数调用的结果。
B.    不要返回局部对象的引用或指针,局部对象会在函数调用结束的时候释放内存;
C.    引用返回的是左值;

//返回值为常饮用出现的错误之一

const string &manip()
{
string ret;//以某种方式改变一下ret
if (!ret.empty())
return ret; //错误:返回的是对局部变量的引用
else
return "Empty"; //错误:"Empty"是一个局部临时量
}

//  有的返回值也是局部变量,但是不会提示错误~~~

1>e:\c程序\finalconst\finalconst\finalconst.cpp(10): warning C4172: 返回局部变量或临时变量的地址
1>e:\c程序\finalconst\finalconst\finalconst.cpp(12): warning C4172: 返回局部变量或临时变量的地址

6. 数组形参

A.    数组的性质:不允许拷贝数组,使用数组时通常会将其转换成指针;
因而函数传递数组时,实际上传递的是指向数组首元素的指针。
B.    首先需要看一下三种等价的形参是数组的形式
void  print(const int*);
void print (const int[]);//可以看出来,函数的意图是作用于一个数组
//因而 void print(const int *arr[])==void print (const int **arr)
void print (const int[10]); //这里的维度表示我们期望数组含有多少元素实际不一定
这里每个函数的唯一形参都是const int * 类型,这是一个底端const

exe1:当形参为内置类型,不是混合类型(如指针、引用)

void reset(int ival)
{
ival = 3;
cout << ival << endl;
}
int main()
{
int ival1 = 5;
reset(ival1);
cout << ival1 << endl;
}

//输出值为3,5

exe2:当形参为指针类型的时候

void reset(int *ival)
{
*ival = 3;
cout << *ival <<" "<< ival << endl;//当传递的值为指针的时候,可以在函数体内

//通过指针改变指对象的值,并且该值被传回主函数,间接地改变主函数中所指地址中的值;

int ival2 = 4;
ival = &ival2;//改变函数传入的实参的值,也就是改变传入地址的值,仅仅是局部变量的拷贝,

//并不能使实参的值改变,如果注释掉*ival = 3;该函数调用不会改变主函数的任意值

}
int main()
{
int ival1 = 5;
reset(&ival1);
cout << ival1 <<" "<<&ival1<< endl;
}

输出值为:3,002AFB04

        3,002AFB04

exe:当形参为引用类型的时候

void reset(int &ival)
{
ival = 3;
cout << ival << " " << &ival<< endl;
}
int main()
{
int ival1 = 5;
reset(ival1);
cout << ival1 << " " << &ival1 << endl;
}

输出值为:3,002AFB48

         3,002AFB48

exe:当形参为内置类型时,在函数体内定义的变量是局部变量,但是仍然可以将值赋给主函数中的某个变量~~,这是值传递~~

int fact(int val)
{
int ret = 1;
while (val > 1)
ret *= val--;
return ret;
}

int main()
{
int j = fact(5);
cout << "5! is " << j << endl;
return 0;
}

exe:当形参是未知个数,但是类型相同的时候,可以用类initializer_list

void error_msg(initializer_list<string> i1)
{
for (auto beg = i1.begin(); beg != i1.end(); ++beg)
cout << *beg << " ";
cout << endl;
}
int main()
{
string expected;
string actual;
if (expected != actual)
error_msg({ "functional", expected, actual });
else
error_msg({ "functional", "okay" });
return 0;
}

最后当指针出现的各种情况的总结:

 1 #include <iostream>
 2 #include <string>
 3 #include<vector>
 4 using namespace std;
 5
 6
 7 int g_val = 8;
 8 //数组的数组
 9 void  pointer(int *ival)
10 {
11     *ival = 10;
12     cout << *ival << " " << ival << endl;
13     //在此处应该是把实参的值改为10,并且地址应该相同
14 }
15 void  pointer1(const int *ival)
16 {
17     cout << *(ival + 2) << endl;
18     //输入的是数组的首地址,该地址的值不能改变,但是指针能向下移动
19 }
20 void pointer2(int *arr[])
21 {
22     cout <<**arr<<" "<< *arr << " " << arr << endl;
23 }
24 void pointer3(int(*arr)[4])//等价于void pointer3(int(arr[])[4])
25 {
26     for (size_t i = 0; i < 4; i++)
27     {
28         cout << (*arr)[i] <<" "<<arr[i]<< endl;//对指针数组的使用~
29     }
30 }
31 int *pointer4()//有意义的为int * const pointer4()
32 {
33
34     return &g_val;//可以在类的使用中返回该值的地址,可以用于修改该对象的值;
35 }
36
37
38 int main()
39 {
40     int val = 4;
41     int val1[4] = { 0, 1, 2, 3 };
42     int val2[2][4] = { 0, 1, 2, 3, 4, 5, 6, 7 };
43     int *val3 = &val;
44     //多维数组初始化-----
45     //还可以初始化{{0,1,2},{3,4,5}}
46
47     //test void  pointer(int *ival)
48     pointer(&val);
49     cout << val << " " << &val << endl;
50     pointer(val1);
51     cout << val1[0] << " " << val1 << endl;
52     //test void  pointer1(const int *ival)
53     pointer1(val1);
54
55     //test void pointer2(int **arr)
56     pointer2(&val3);
57     //void pointer3(int(*arr)[4])
58     pointer3((val2+1));
59     //test int  *pointer4()
60     int *val4=pointer4();
61     cout << val4 << " " << *val4 << endl;
62     *val4 = 90;
63     cout << val4 << " " << *val4 << endl;
64     return 0;
65 }

实验结果:

参考:

  函数返回值是否使用引用类型的问题:理解引用、返回值
  1. http://blog.csdn.net/sxhelijian/article/details/7466540

理解一般指针类型

  1. http://www.cnblogs.com/dzry/archive/2011/05/12/2044835.html
时间: 2024-10-17 17:13:50

引用&&指针&&返回值&&定义声明&&生命周期&&const的相关文章

Activity的跳转及返回值,activity的生命周期

Activity生命周期 从创建到销毁的生命周期: onCreate()→onStart()→onResume()→onPouse()→onStop()→onDestroy() 从起动到后台再到前台: onCreate()→onStart()→onResume()→onPouse()→onStop()→onRestart()→onStart()→onResume() 启动第二个activity 1. 创建new activity 2. 创建对应的new xml布局文件 3. 在new activ

【03】指针、返回值、成员函数的const

1 // 2 // 2015-03-05 03/55 3 // 指针.返回值.成员函数 之 const 4 // 5 6 #include <iostream> 7 #include <string> 8 9 using namespace std; 10 11 // ------------------------------ 12 // 1. 指针的const 13 // ------------------------------ 14 const char *p1 = &q

为什么赋值操作符函数的参数为const引用,返回值为引用

为什么赋值操作符函数的参数为const引用,返回值为引用 1.返回值类型 返回类型一般声明为类型的引用,并在函数结尾时返回实例自身的引用(即*this).这里主要有两个原因:(1)返回引用可以减少一次拷贝构造和析构函数导致不必要的开销,因为返回值类型不是引用,会创建一个匿名对象,这个匿名对象时个右值,获取return的值.(2)可以实现连续赋值 在例子中 b=c=a; 返回值不是引用类型也是可以的,其运算顺序 b=(c=a); c得到一个右值,再将右值赋给b,所以逻辑上没有问题的.但是如果是 (

标量类型与返回值类型声明

PHP 标量类型与返回值类型声明  PHP 7 新特性 标量类型声明 默认情况下,所有的PHP文件都处于弱类型校验模式. PHP 7 增加了标量类型声明的特性,标量类型声明有两种模式: 强制模式 (默认) 严格模式 标量类型声明语法格式: declare(strict_types=1); 代码中通过指定 strict_types的值(1或者0),1表示严格类型校验模式,作用于函数调用和返回语句:0表示弱类型校验模式. 可以使用的类型参数有: int float bool string inter

GetLastError的使用和返回值定义大全

GetLastError返回的值通过在api函数中调用SetLastError或SetLastErrorEx设置.函数 并无必要设置上一次错误信息,所以即使一次GetLastError调用返回的是零值,也不能 担保函数已成功执行.只有在函数调用返回一个错误结果时,这个函数指出的错误结果 才是有效的.通常,只有在函数返回一个错误结果,而且已知函数会设置GetLastError 变量的前提下,才应访问GetLastError:这时能保证获得有效的结果.SetLastError函 数主要在对api函数

c++ vector 指针返回值问题

关于Vector作为函数的返回值,有几点需要说明: 1.首先如果Vector是一个局部的变量,那么返回该Vector的引用是十分危险的,因为在Vector超出作用域的,会自动调用相关的析构函数(~Vector()),如果Vector中存放的是类(ClassName)对象的指针,则不会调用相关的类ClassName析构函数,只会把相关的空间清空(也就是Vector.size()=0),这样会造成内存泄露.但是如果Vector中存放的是类(ClassName)的对象,则会调用相关的类ClassNam

C++把引用作为返回值

当返回一个引用时,要注意被引用的对象不能超出作用域.所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用. int& func() { int q; //! return q; // 在编译时发生错误 static int x; return x; // 安全,x 在函数作用域外依然是有效的 }

引用参数与引用返回值 类的拷贝构造

引用地址  http://www.cnblogs.com/bigshow/archive/2008/11/10/1330514.html 经常看到这样的声明:T& func(T& t),这种声明和T func(T t)有什么区别?书上的解释是为了提高效率,究竟是如何提高效率的呢?内部执行了什么操作?本文通过8个小例子对引用参数和引用返回进行了一次彻底的排查.    首先看一下在类的成员函数中的引用参数和引用返回值: 类定义class A{     public:      int x; A

C-const和static的区别, 指针作为函数的返回值, 指向函数的指针, 枚举

const和static的区别 const ——只读, 只在声明中使用 1 const int num = 10; 2 int const num = 10; num变量只读, 不能修改 1 const int arr[4] = {10, 20, 30, 40 }; 2 int const arr[4] = {10, 20, 30 ,40 }; 数组的元素的值不能被修改, 只读 1 const int *p1 = &num; 2 int const *p1 = &num; 无法通过p1指针