C++ 引用
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
#include <stdio.h>
int main()
{
int a = 100;
int &b = a;
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("addr: a = %p\n", &a);
printf("addr: b = %p\n", &b);
}
打印结果:
a = 100
b = 100
addr: a = 0xbf8931f8
addr: b = 0xbf8931f8
C++ 引用 vs 指针
引用很容易与指针混淆,它们之间有三个主要的不同:
- 不存在空引用。引用必须连接到一块合法的内存。
- 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
- 引用必须在创建时被初始化。指针可以在任何时间被初始化。
C++ 中创建引用
把引用作为参数
C++ 支持把引用作为参数传给函数,这比传一般的参数更安全。
C++ 函数传参:
-
将变量名作为实参和形参。这时传给形参的是变量的值,传递是单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。// 同 c
-
传递变量的指针。形参是指针变量,实参是一个变量的地址,调用函数时,形参(指针变量)指向实参变量单元。这种通过形参指针可以改变实参的值。// 同 c
-
C++提供了 传递变量的引用。形参是引用变量,和实参是一个变量,调用函数时,形参(引用变量)指向实参变量单元。这种通过形参引用可以改变实参的值。
//交换两个变量的值,且不使用第三方变量 void swap(int *p, int *q) { *p ^= *q; *q ^= *p; *p ^= *q; } int swap(int &a,int &b) { a ^= b; b ^= a; a ^= b; } int main(int argc, const char *argv[]) { int a = 10; int b = 5; printf("a = %d, b = %d\n", a, b); //swap(&a, &b); swap(a,b); printf("a = %d, b = %d\n", a, b); return 0; }a = 10, b = 5
a = 5, b = 10
把引用作为返回值
可以从 C++ 函数中返回引用,就像返回其他数据类型一样
通过使用引用来替代指针,会使 C++ 程序更容易阅读和维护。C++ 函数可以返回一个引用,方式与返回一个指针类似。当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。
#include <iostream>
using namespace std;
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues( int i )
{
return vals[i]; // 返回第 i 个元素的引用
}
// 要调用上面定义函数的主函数
int main ()
{
cout << "改变前的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
setValues(1) = 20.23; // 改变第 2 个元素
setValues(3) = 70.8; // 改变第 4 个元素
cout << "改变后的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
return 0;
}
- 以引用返回函数值,定义函数时需要在函数名前加 &
- 用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
引用作为返回值,必须遵守以下规则:
- 不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
- 不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一 个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
- 可以返回类成员的引用,但最好是const。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常 量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
默认参数
#include <stdio.h>
void debug(const char *ptr = "---------------")
{
printf("%s\n", ptr);
}
int main(int argc, const char *argv[])
{
debug();
debug();
return 0;
}
有以下三个要注意的情况。
-
默认参数只能放在函数声明处或者定义处,能放在声明处就放在声明处 。
a. 大部分情况,别人调用你的代码只能看到函数声明,如果你写在定义处,别人根本不知道你的默认参数是什么。
b.如果你是在定义处写的默认参数,那么你在使用该函数前就需要把函数定义放在前面。不然编译阶段通过无默认参数的函数声明无法确定这个函数是带默认参数的。
所以,默认参数写在声明处啊。 -
如果某个参数是默认参数,那么它后面的参数必须都是默认参数
因为非默认参数的参数必须要给出具体值,而调用函数传递参数的时候是从左到右的,所以非默认参数前面的都 必须要传值进来。那么默认参数后面的当然也得都为默认参数。 -
.不要重载一个带默认参数的函数
class Test { public: int func(int a) { return a; } int func(int a, int b = 1) { return a + b; } } ; //你调用func(1)的时候,谁知道你想调用哪一个。
函数重载
-
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载
-
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
-
当调用一个重载函数时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数的过程,称为重载决策。
-
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。
#include <iostream> using namespace std; class printData { public: void print(int i) { cout << "整数为: " << i << endl; } void print(double f) { cout << "浮点数为: " << f << endl; } void print(char c[]) { cout << "字符串为: " << c << endl; } }; int main(void) { printData pd; // 输出整数 pd.print(5); // 输出浮点数 pd.print(500.263); // 输出字符串 char c[] = "Hello C++"; pd.print(c); return 0; }
当上面的代码被编译和执行时,它会产生下列结果:
整数为: 5
浮点数为: 500.263
字符串为: Hello C++
堆内存
-
new(新建)用于新建一个对象。new 运算符总是返回一个指针。由 new 创建
-
delete(删除)释放程序动态申请的内存空间。delete 后面通常是一个指针或者数组 [],并且只能 delete 通过 new 关键字申请的指针,否则会发生段错误。
#include <stdio.h> #include <malloc.h> #include <string.h> int main(int argc, const char *argv[]) { /* char *p = (char*)malloc(10); strcpy(p,"hello"); puts(p); free(p); */ int *p = new int; *p = 100; printf("*intp = %d\n", *p); delete p; char *str = new char [10]; strcpy(str, "hello"); puts(str); delete [] p; return 0; }
打印信息
*intp = 100
hello
335

被折叠的 条评论
为什么被折叠?



