1.C和C++的指针
2.引用
3.拷贝构造函数
4.成员指针
一、指针
指针可以存储一个地址,当定义一个指针的时候,必须表明它所指向的类型,并且应该进行初始化(避免成为野指针)。最常见的使用指针的情况就是改变他所指向的值。
int a=0;
int *ipa = &a;
C++允许将任何类型的指针赋给void*,但是不允许将void*类型的指针赋给任何其他类型的指针(尽管这是在C语言中允许的)。实际上把void*当成了一个仓库,可以随时往里面放货物,但是在取货物的时候,必须考虑取出来的是货物,而不是仓库的老鼠。例如:
int i = 10;
int *p = &i;
void *vp = p;
//int *ip =vp;//ERROR,不允许将void*类型赋给其他任何类型
int *ip = (int *)vp;//除非进行强制类型转换
二、引用
引用(reference)通常用于函数的参数表和返回值 ,但是也可以独立的使用,可以粗略地把引用理解为取别名(&)
1引用在创建的时候必须被初始化,这一点区别于指针并且比指针更安全,毕竟在程序运行的时候,没人知道一个没有初始化的野指针指向哪里。
2一旦一个引用被初始化以后,不再可以令他引用另外一个对象,这区别于指针,因为指针可以随时指向另外一个对象。
3同样,是不存在空的引用,类似于取别名,它必须依托于相应的存储空间,必须确保引用和一块合法的存储空间关联。区别于指针可以指向NULL。
对于函数中的引用,最常见的是在函数参数和返回值中。当引用被用作函数参数的时候,函数内任何对引用的更改将会对函数外的参数产生变化。如果从函数返回一个引用,就必须如同函数返回一个指针一样对待,函数返回的时候不论引用关联什么都应该存在。
例如在int &(){}中,由于返回值是一个int类型的引用,而对于函数内部的Int q= 0;,作用范围只在函数内部,当退出这个int &h(){}时,int q= 0;将会被销毁,因此,返回q的引用将是不安全的,而对于static int x = 1;将会被存储在静态数据区,在main()函数结束的时候才会被销毁,因此可以返回x。
在上面这个例子中,可以看出,函数的返回值是x y中较大的值的引用,因此在后续的
returnmax(a,b) = 3.3;
· 可以看做
int &c = returnmax(a,b);
c=3.3;
把x y中较大的数修改为了3.3
但在有时候,我们往往需要将临时变量作为参数,这时候就需要常量引用。
对于临时变量,作用域很可能仅限于这一行函数调用,在运行到下一行前就被销毁,因此对临时变量的改变很可能没有任何一样,所以对于普通类型的引用,将不允许临时变量的传入。
常量引用可以解决这个问题。这意味着这个函数不会改变参数,或者只能调用常量成员函数而不引起数据成员的改变。通过常量引用,我们才能接受一个临时对象,这个临时对象可能是来自另一个函数的返回值又或者是来自函数使用者显式创建的。临时对象默认总是不变的。
类似的,我们也可以将一个引用指针作为函数的参数传入。
可以看出,这个引用改变了指针的指向,使它成为了野指针。
三、拷贝构造函数
拷贝构造函数的产生是我们希望从现有的对象中产生新的对象,同时可以避免位传递的缺陷。
如果使用位拷贝,在多数情况下可行,但是需要对初始化进行操作的时候(例如计数),就行不通,因为初始化不是简单的拷贝。另外,如果在类的内部含有指针又会出现新问题:指针指向哪里?是否拷贝指针的指向?指针指向内存的分配?
我们可以使用拷贝构造函数来解决这些问题。每当需要从已有的对象创建新的对象的时候,可以通过定义自己的函数来做这件事,因为是创建对象,所以这个函数是一个构造函数,并且传递给这个函数的单一参数必须是源对象。但是这个源对象不能按值传递,因为要定义的函数要解决的正是按值传递的问题。这时候引用就起作用了,可以使用源对象的引用,这个函数就称之为拷贝构造函数,他经常被称为X(const X&)。
拷贝构造函数常见的应用:
1.根据源对象创建新对象
2.当函数按值传递对象的时候或者返回一个对象(会创造一个一模一样的新临时对象,其中用到了拷贝构造函数)