函数按值、按址传参、返回与接收所有情况研究

本文详细探讨了C++中函数参数按值、按址传递以及返回的情况,包括对象的关系、存储位置和生命周期。通过多个示例分析了不同情况下对象的构造、复制、析构过程,揭示了函数调用原理和指针在其中的作用。

注意:每种情况均需要了解:

各个对象(变量)关系、存储位置和生命周期。其实就是对C++中存储模型,函数调用原理,指针等的综合考量。

 

1    按值传递,按值返回,返回参数

using namespace std;

class A{
public:
 A();
 A(A& one);
 ~A();
 void set(int i){ x = i;}
 void get(){cout<<x<<endl;}
private:
 int x;
};

A::A()
{
 cout<<"执行构造函数创建一个对象\n";
}
A::A(A &one)
{
 cout<<"执行复制构造函数创建该对象的副本\n";
}

A::~A()
{
 cout<<"执行析构函数删除该对象\n";
}

A func(A one)
{
 return one;
}

int main()
{
 A a;
 func(a);

 return 0;
}


执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
执行复制构造函数创建该对象的副本
执行析构函数删除该对象
执行析构函数删除该对象
执行析构函数删除该对象
Press any key to continue
-------------------------------------------------------------
A func(A one)
{
 return one;
}

int main()
{
 A a;
        A b = func(a);

 cout<<"---------\n";
 return 0;
}

执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
执行复制构造函数创建该对象的副本
执行析构函数删除该对象
--------
执行析构函数删除该对象
执行析构函数删除该对象
ress any key to continue

结论:

返回对象是参数对象的复制

参数对象在栈
返回对象在栈

参数对象在函数结束时立即消失
返回对象如果被引用就在调用函数周期中

补充:
且 A b就是第二次复制的那个对象,没有再次进行拷贝。

 

2      按址传递,按址返回,返回参数

A &func(A &one)
{
 return one;
}

int main()
{
 A a;
 func(a);

 return 0;
}

执行构造函数创建一个对象
执行析构函数删除该对象
Press any key to continue

 

3        按值传递,按址返回,返回参数

A &func(A one)
{
 return one;
}

int main()
{
 A a;
 func(a);

 return 0;
}
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
执行析构函数删除该对象
执行析构函数删除该对象
Press any key to continue
---------------------------------------------------------
A &func(A one)
{
 return one;
}

int main()
{
 A a;
        A b = func(a);

 cout<<"---------\n";
 return 0;
}

执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
执行析构函数删除该对象
执行复制构造函数创建该对象的副本
--------
执行析构函数删除该对象
执行析构函数删除该对象
ress any key to continue
--------------------------------------------------
A &func(A one)
{
 cout<<&one<<endl;
 return one; 
}

int main()
{
 A a;
    A &b = func(a);
 
 cout<<"---------\n";
 cout<<&b<<endl;
 return 0;
}
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
0012FF0C
执行析构函数删除该对象
---------
0012FF0C
执行析构函数删除该对象
Press any key to continue
----------------------------------------------
A &func(A one)
{
 cout<<&one<<endl;
 one.set(2);
 one.get();
 return one; 
}

int main()
{
 A a;
 a.set(1);
        A &b = func(a);

 cout<<&b<<endl;
 b.get();
 return 0;
}
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
0012FF0C
2
执行析构函数删除该对象
0012FF0C
4200635
执行析构函数删除该对象
Press any key to continue
----------------------------------------------------------
结论:
关系、存储位置、生命周期

关系
参数对象是由a复制,函数结束,参数对象析构,返回的是参数对象的地址,所以(实验二)b就是复制了one,但是因为one已经析构,
所以b复制的值是随机的地址是一样的,如实验四,但是实验四&b不用再复制。

存储位置
one是在栈,实验二b也是在栈。

生命周期
one函数结束就析构,实验二b在调用函数的周期中。

4        按址传递,按值返回,返回参数

A func(A &one)
{
 return one; 
}

int main()
{
 A a;
 A b = func(a);
 cout<<"------\n";

 return 0;
}
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
------
执行析构函数删除该对象
执行析构函数删除该对象
Press any key to continue
------------------------------------------------
A func(A &one)
{
 one.set(1);
 return one; 
}

int main()
{
 A a;
        A b = func(a);
 b.get();
 a.get();
 cout<<"------\n";

 return 0;
}

执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
858993460
1
-----
执行析构函数删除该对象
执行析构函数删除该对象
ress any key to continue
--------------------------------------------------
疑问:
返回时的复制对象应该就是a,而a还未析构,应该也将x = 1复制过来,但是却是随机数

5        按值返回,返回非参堆对象

A func()
{

 A * p = new A;
 p->set(1);
 return *p; 
}

int main()
{
 
    A &r = func();

 r.get();

 return 0;
}
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
858993460
执行析构函数删除该对象
ress any key to continue
-------------------------------------
再一次证明返回值复制是在析构之后,同时对于4中问题也有同样反映,p指向的对象并未析构,但是复制得到的是一个随机数,难道
无论复制对象是不是在其复制前析构都只是不能复制数据吗。

导致了内存泄露,p会消失;r所引用的对象无法使用delete删除,因为是在栈区域。

6         按址返回,返回非参堆对象

A & func()
{
 A * p = new A;
 p->set(1);
 return *p; 
}

int main()

        A &r = func();
 r.get();
 delete(&r);
 return 0;
}
执行构造函数创建一个对象
1
执行析构函数删除该对象
Press any key to continue

7        按值返回,返回非参栈对象

A func()
{
 A p;
 p.set(1);
 return p; 
}

int main()
{
 
        A &r = func();
 r.get();
 return 0;
}
执行构造函数创建一个对象
执行复制构造函数创建该对象的副本
执行析构函数删除该对象
858993460
执行析构函数删除该对象
ress any key to continue

8        按值返回,返回非参栈对象

A& func()
{
 A p;
 p.set(1);
 cout<<&p<<endl;
 return p; 
}

int main()
{
 
        A &r = func();
 r.get();
 cout<<&r<<endl;
 return 0;
}

执行构造函数创建一个对象
0012FF18
执行析构函数删除该对象
-858993460
0012FF18
Press any key to continue


----------------------------------
返回值就是函数p对象地址,因为函数结束了,p就析构,值就成随机的了。

9         补充

1 在函数中声明的临时对象存储在栈中,生命周期是到函数结束。
2 动态new的对象是在对中,生命周期是整个程序执行结束。
3 引用接受返回引用,不会复制;引用接受返回对象,不会复制;对象接受返回对象;不会复制;对象接受返回引用,会复制.
4 返回函数是对象就得复制,参数对象析构是其复制之前完成的。

 

对象不能直接访问private,protected,可以访问public
类中的函数可以访问private,protected,public成员。
派生类只能继承类的public和protected,且公有继承保持不变。私有派生类的protected和public都变成私有的了。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值