class A
{
public :A(int a)
{
b=a;
c++;
cout<<"construct A()"<<b<<"c"<<c<<endl;
}
A()
{
c++;
cout<<"non argument method"<<b<<"c"<<c<<endl;
}
A(const A&a)
{
this->b=a.b;
c++;
cout<<"copy construct method"<<b<<"c"<<c<<endl;
}
~A()
{
c--;
cout<<"destroy method"<<b<<"c"<<c<<endl;
}
int b;
static int c;
};
int A::c=0;
class B
{
private: A a;
public:
B(A a)
{
cout<<"here"<<endl;
this->a=a;
cout<<"here1"<<endl;
}
};
A g();
int main()
{
A a=g();
cout<<"asd"<<endl;
system("pause");
}
A g()
{
A a=A(2);
cout<<"here"<<endl;
A c=a;
cout<<"here1"<<endl;
return NULL;
//B b=B(a);
//return a;
}
结果
construct A()2c1
here
copy construct method2c2
here1
construct A()0c3
destroy method2c2
destroy method2c1
asd
请按任意键继续. . .
1程序首先进入到函数g里面,先调用A的有参构造;
2 A c=a; 这一段调用A的拷贝构造函数,没有异议。 如果将程序改为 A c; c=a; 程序将不会调用拷贝构造函数,而是调用系统默认的=操作符。
3 函数有返回值,并且返回值为值对象,所以调用默认
将程序的返回值改为 return a;
结果
construct A()2c1
here
copy construct method2c2
here1
copy construct method2c3
destroy method2c2
destroy method2c1
asd
请按任意键继续. . .
函数返回时程序调用A的拷贝构造函数(其中这个拷贝函数的参数为a)产生一个临时对象,该临时对象有个指针指向这个对象,该指针存储在寄存器中,当函数的堆栈销毁了,但是里面的值并没有擦除,所以依然可以借助这个寄存器的指针得到函数返回的这个临时对象的值。函数结束时先要销毁c对象(因为为自动变量存储在堆栈中先进后出原则),然后销毁a,最后函数执行完,再去销毁函数返回时调用拷贝构造函数产生的临时对象。如果你返回的Null则调用的会是普通的单个参数为int 型1的构造函数,如果没有程序则会报错。(如果你没有一个并且只有一个参数为int
的构造函数,系统尝试调用默认的拷贝构造函数,调用过程中会出现类型转换错误,将值1(null)转为const & xxx)。
如果函数返回的对象在调用的地方有存储(即上例中在main函数中 A a=g())则所谓的函数返回时创建的临时对象其实不是临时对象而是一个在main结束才释放的对象。
如果一个对象先声明(一般的声明和定义在同一语句中),在做赋值的话那么它将不会调用拷贝构造函数。即在对象的初始化中才会调用拷贝构造函数。