4.1c++学习记录之传递对象

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;//按别名返回
	}

总结:

按值传递,在传递过程中需要复制对象,因此 会调用复制构造函数,该函数的作用就是创建某个临时副本,只要在栈中创建临时副本都会自动调用复制构造函数.
**按地址传递:**没有调用复制构造函数,也就没有输出复制构造函数的信息.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值