C++拷贝构造传参解读——剑指offer

C++中为什么不允许复制构造函数传值参数呢?如果采用传值方式定义复制构造函数会发生什么呢?下面进行解答。
关于下面那程序执行时出现编译错误的问题,程序来源《剑指offer》。

  • 代码1
class A
{
public:
	A(int n) { value = n; }
	A(A other) { value = other.value; }
	void printA() {
		cout << "value = " << value << endl;
	}
private:
	int value;
};

int main(void) {
	A a1 = 10;
	A a2 = a1;
	a2.printA();
	system("pause");
	return 0;
}

按照代码执行顺序分析原因:

  1. 问题出在A a2 = a1;这句代码中,在这句代码执行时,根据c++特性,会调用类A的拷贝构造函数(关于拷贝构造函数,当没有显式定义时会有默认的拷贝构造函数,且以浅拷贝的方式实现的)。类A中定义了拷贝构造函数A(A other) { value = other.value; },则调用此段代码。
  2. 当程序执行到拷贝函数时,由于类A的拷贝构造函数采用了值传递的方式,对于值传递,当实参a1传入时,会在栈中创建一个a1的复制体(也相当于一个中间变量),假设此变量名为temp1,这样拷贝构造函数中的语句value = other.value;可以看做类似于a1.value = temp1.value;,通过复制体temp1完成对实例a1中value属性的赋值。
  3. 问题的关键来了,这个复制体是如何得到的呢?答案是这个复制体是由类A的拷贝构造函数生成的,也就是类似于执行了A temp1 = a1;这样一段语句,生成temp1存于栈中
    注: 关于这个复制体是否是由A的拷贝构造函数生成的可以看下面的代码2,类A的构造函数中有一个是对类B的拷贝,也采用了值传递的方式,可以在运行结果中看到在调用这个构造函数时会执行类B的拷贝构造函数。
  4. 这时再看3中A temp1 = a1;语句,是否感觉似曾相识,看1中A a2 = a1;你会发现它们是几乎一样的。这样在生成temp1的过程中和生成a2的过程类似,也需要调用类A的拷贝构造函数,在执行拷贝构造函数的过程中也会生成中间变量temp2,执行A temp2 = a1;,然后生成temp3、temp4……如此递归下去,由于生成的中间变量都是存放在栈中的,所以会导致栈溢出,好在编译器一般都不允许我们这样做,直接报编译错误。

下面是一段用于理解上面内容的代码。

  • 代码2:
#include <iostream>
using namespace std;

class B
{
public:
	int value;
	B(int n) { value = n; }
	B(const B &other) { // B类型的拷贝构造函数
		cout << "class B 拷贝构造函数被调用!" << endl;
		value = other.value; 
	}
};

class A
{
public:
	A(int n) { value = n; }
	A(const A &other) { value = other.value; }
	A(B other) { value = other.value; }	// 此处会调用B的拷贝构造函数
	void printA() {
		cout << "value = " << value << endl;
	}
private:
	int value;
};

int main(void) {
	A a1 = 10;
	B b = 20;
	A a2 = b;
	a1.printA();
	a2.printA();
	system("pause");
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值