c++学习记录之引用
2018年5月9日14:39
###传递对象
**按值来传递对象:**默认调用复制构造函数
class A
{
...
A();
A(A&);
~A();
}
A func(A one);
int main()
{
A a;
func(a);
return 0;
}
A func(A one)
{
return one;
}
**按地址传递:**没有调用复制构造函数,也就没有输出复制构造函数的信息.
int main()
{
A a;
func(&a);
}
A * func(A *one)
{
return one;
}
假如我们将函数声明为
A func(A *one)
,那么由于它返回的是对象而不是该对象的内存地址,因此在返回该对象时仍然需要调用复制构造函数来复制对象.
返回类型和返回值
A *func(A *one)//返回类型是指针地址,若没加*,则会报错,因为没有星号返回类型是对象,与返回值为地址不匹配
>{return one;//返回值是地址
}
consnst指针传递对象
采用指针来传递对象,虽然可以避免调用复制构造函数和析构函数,但是由于它得到了该对象的内存地址,可以随时修改对象的数据,因此它实际上是破坏了按值传递的保护机制。const指针来传递对象,这样可以防止任何试图对该对象所进行的操作行为,并且保证返回一个不被修改的对象。
# const A * const func(const A *const one)// 保证传递来的数据和返回的数据都不会被修改
使用引用传递对象
引用始终是个常量
A& func(A &one)
{
return one}//
int main()
{
A a;
a.set(11);
A &b=func(a);//func返回a对象的别名,b引用作为a的别名的别名。若b不加&则输出会报错(输出复制构造函数随机数),即不能用新对象接收返回来的 别名,必须用一个引用接受返回的引用。
b.set(11);//可以修改
return 0;
}
const A& func( const A &one) //括号外的const决定了返回类型是常量,因此调用该函数时 `A const &b=func(a);`zu
{
//one.set(33);//one所引用对象a受到保护(形参const A& one 决定了)。one是个别名,而别名是个常量。从而进来的数据不能修改,返回的数据也不能修改。
return one}
int main()
{
A a;
a.set(11);
A const &b=func(a);//b引用作为a的别名。若b不加&则输出会报错.右边返回来的常量,所以也要加const
// b.set(11);//b是别名常量了,不能修改了。
}
到底使用指针还是应用呢
指针可以为空
int main()
{
int a=1;//引用只能被初始化,不能赋为另一个对象的别名,因此引用不能只想不同的对象。
int &p=a;
int b=9;
&p=b;
return 0;
//int &r=new int;错误,
int *&r=new int;//正确,r可以看成指针,只是别名。不建议用
*r=3;//机器虚拟内存太小的情况下,空引用。
return 0;
}
另外例子:
int *p=new int;
if(p!=NULL){
int &r=*p;//p指向内存空间指向的数据的别名
r=3;
}
引用指针一起使用
int *p,ra;
引用容易出现的错误[重要]
class A{
public:
A(int i){x=i;}
A(A&a){this->x=a.x;}//不创建会提供默认复制构造函数
int get(){return x;}
pivate:
int x;
};
/*去掉引用运算符输出23正确。即A func()按值返回对象会自动调用默认的复制构造函数创建一个副本*/
A &func()
{
A a(23);
returrn a;//将该对象别名返回,对象a是局部对象,func结束后删除,返回不存在的别名.按值返回对象时会自动调用默认复制构造函数,创建一个对象a的副本,将对象x复制给对象a副本,结束时调用析构函数
}
int main()
{
A &r=func();//用别名接收返回的别名
//A *r=&func();//使用指针
cout<<r.get()//
return 0;};
1310159
引用一个按地址返回的堆中对象
A func()
{
A *P=new A(99);
return *p;//堆中空间需要用delete删除,否则造成内存泄露.返回的是堆中对象的副本.
/* *p是读取p指向的数据,而p指向的是堆中对象,等于返回p指向的堆中对象,因此在按值返回*p时又调用复制构造函数创建一个堆中对象的副本,该副本不是由程序员使用new来创建的,因此会保存在栈中.同时,由于指向堆中空间的P指针*/
}
int main()
{
A&r=func();
return 0;
}
引用一个按别名返回的堆中对象
int main()
{
A &r=func();
A *pa=&r;
delete pa;
return 0;
}
A &func()
{
A *p=new A(99);
return *p;
}
在哪创建在哪里释放
int main()
{
A *p=new A(99);
func(*p);
cout<<p-get();
delete p;
return 0;
}
A &func(A&a)
{
a.set(66);
return a;//按别名返回
}
总结:
按值传递,在传递过程中需要复制对象,因此 会调用复制构造函数,该函数的作用就是创建某个临时副本,只要在栈中创建临时副本都会自动调用复制构造函数.
**按地址传递:**没有调用复制构造函数,也就没有输出复制构造函数的信息.