C++编程思想笔记——引用和拷贝构造函数

引用是支持C++运算符重载的语法基础

C和C++指针的最重要区别,在于C++是一种类型要求更强的语言。C不允许随便吧一个类型的指针指派给另一个类型,但允许通过void*来实现,例如:

bird* b;  rock* r;   void* v;   v=r;   b=v; C++不允许这样做。如果真想这么做,必须显示地使用映射。

1.C++中的引用

引用(&)像一个自动能被编译器逆向引用的常量型指针。它通常用于函数的参数表中和函数的返回值,单页可以独立使用。当创建引用时,引用必须被初始化指向一个存在的对象,但也可以这样写:
int& q = 12;这里,编译器分配了一个存储单元,它的值被初始化为12,这样这个引用就和这个存储单元联系上了。要点是任何引用必须和存储单元联系。但访问引用时,就是在访问那个存储单元。考虑一个引用的最简单的方法是把它当做一个奇特的指针。这个指针的一个优点是不必怀疑它是否被初始化了(编译器强迫它初始化),也不必知道怎样对它逆向引用(这由编译器做)。
使用引用有一定规则:
1.当引用被创建时,它必须被初始化。(指针则任何时候可以被初始化)
2.一旦一个引用被初始化为指向一个对象,它就不能被i改变为对另一个对象的引用(指针则另有在任何时候指向另一个对象)
3.不可能用NULL引用。必须保证引用是和一块合法的存储单元关联。
1.1函数中的引用
常量引用
如果从函数中返回一个引用,必须向从函数中返回一个指针一样对待。当函数返回时,无论引用关联的是什么都不应该离开,否则,将不时代扫指向哪一个内存区域。
在函数参数中使用常量引用特别重要。这是因为我们的函数也许会接受临时的对象,这个临时对象是由另一个函数的返回值创立或由函数使用者显式地创立的。临时对象总是不便的,因此如果不使用常量引用,参数将不会变被编译器接受。
void f(int&) {}
void g(const int&) {}

main() {
    //f(1);    //error
    g(1);
}
指针引用
在C语言中,如果想改变指针本身而不是它所指向的内容,函数声明可能想这样:
void f(int**);
对于C++中的引用,语法更加清晰void(int*&)
1.2参数传递准则

2拷贝构造函数

传递和返回大对象
如果创建了一个类,我们希望传递改类的一个对象,首先了解编译器调用函数时对编译器的约束
函数调用栈的框架
当编译器为函数调用产生代码时,它首先把所有参数压栈,然后调用函数。在函数每部,产生代码,向下移动栈指针为函数局部变量提供存储单元。在汇编语言CALL中,CPU把程序代码中的函数调用指针的地址压栈,所以汇编语言RETURN可以使用这个地址返回到调用点。当然这个地址是非常神圣的,应为没有它程序会迷失方向。下图是在CALL后栈框架的样子,此时在函数当中已为局部变量分配了存储单元。


函数的其他部分产生的代码完全按照这个方法安排内存,因此它可以谨慎地从函数参数和局部变量中存取而不触及返回地址。函数调用过程中被函数使用的这块内存称为函数框架
重入
因为C和C++的函数支持重点,所以这将出现语言重入的难题。同时,它们也支持函数递归调用。这意味着在程序执行的任何时候,中断都可以发生而不打乱程序。当然,编写中断服务程序(ISR)的作者负责存储和还原他所使用的所有寄存器,但如果ISR需要使用深入堆栈的内存时,就要小心了。(可以吧ISR看成没有参数和返回值是void的普通函数,它存储和还原CPU的状态。有些硬件事件出发一个ISR函数调用,而不是在程序中显式地调用)
现在来想想一下,如果调用函数试图从普通函数中返回,堆栈中的值将会发生什么。因为不能触及堆栈返回地址以上任何部分,所以函数必须在返回地址下降值压栈。但当汇编语言RETURN执行时堆栈指针必须指向返回地址,所以恰好在RETURN语句之前,函数必须将堆栈指针向上移动,以便清除所有局部变量。如果我们试图从堆栈中的返回地址下返回数值,因为中断可能此时发生,此时是我们最容易被攻击的时候。这个时候ISR将向下移动堆栈指针,保存返回地址和局部变量,这样就会覆盖掉我们的返回值。


为了解决这个问题,在调用函数之前,调用者应该在堆栈为返回值分配额外的存储单元。然而C不是按遭这种方法设计的,C++也一样。C++编译器将使用更加有效的方案。
仅当准备用传值的方式传递类对象时,才需要拷贝构造函数
指向成员的指针
struct {
int a;
int b;
};
int simple::*pm = &simple::a;
因为引用到一个类而非那个类的对象,所以没有simple::a的确切地址。因而,&simple::a仅可作为成员指针的语法表示
struct simple2 {
double g(int);
double h(int);
double f(int);
double k(int);
};

double (simlpe2::*fun)(int) = &simple2::f


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值