test1:
1 #include<iostream> 2 using namespace std; 3 class Copy_construction { 4 public: 5 Copy_construction(int a = 0) 6 { 7 this->a = a; 8 cout << "这是有默认参数的构造函数! "; 9 } 10 Copy_construction(const Copy_construction &obj) 11 { 12 cout << "这是拷贝构造函数! "; 13 a = obj.a; 14 } 15 ~Copy_construction() 16 { 17 cout << "一个对象被析构了! "; 18 } 19 private: 20 int a; 21 }; 22 void fuc(Copy_construction t) 23 { 24 cout << "fuc函数! "; 25 } 26 void play_empty(void) 27 { 28 Copy_construction t1;//调用有默认实参的构造函数 29 Copy_construction t2 = t1;//调用拷贝构造函数 30 Copy_construction t3(t2);//调用拷贝构造函数 31 cout << "_________________ "; 32 fuc(t3);//实参初始化形参,调用拷贝构造函数 33 } 34 int main() 35 { 36 play_empty(); 37 38 cout << "hello world! "; 39 return 0; 40 }
运行结果
test2:
修改fuc函数为引用或者指针类型。
1 void fuc(Copy_construction *t) 2 { 3 cout << "fuc函数! "; 4 } 5 6 7 void fuc(Copy_construction &t) 8 { 9 cout << "fuc函数! "; 10 } 11 12 /*****引用或者指针类型调用时不会调用拷贝构造函数****/
test3:
匿名对象的出现:
1 #include<iostream> 2 using namespace std; 3 class Copy_construction { 4 public: 5 Copy_construction(int a = 0) 6 { 7 this->a = a; 8 cout << "这是有默认参数的构造函数! "; 9 } 10 Copy_construction(const Copy_construction &obj) 11 { 12 cout << "这是拷贝构造函数! "; 13 a = obj.a; 14 } 15 ~Copy_construction() 16 { 17 cout << "一个对象被析构了! "; 18 } 19 private: 20 int a; 21 }; 22 Copy_construction fuc(void) 23 { 24 cout << "fuc函数! "; 25 Copy_construction A; 26 return A;//调用拷贝构造函数,生成匿名对象 27 }//运行到该处,先析构对象A,匿名对象是否析构要看怎么去接 28 //如下所示直接调用fuc()则此时匿名对象会被立即析构 29 void play_empty(void) 30 { 31 fuc(); 32 } 33 int main() 34 { 35 play_empty(); 36 37 cout << "hello world! "; 38 return 0; 39 }
如果直接显示调用构造函数,要看怎么去接这个函数, Copy_construction(1);调用之后马上执行析构匿名对象, Copy_construction T= Copy_construction(1);不会马上析构还会转正。
test4:
修改fuc函数的返回类型为引用或者指针:
1 Copy_construction *fuc(void) 2 { 3 cout << "fuc函数! "; 4 Copy_construction A; 5 return &A; 6 } 7 8 Copy_construction &fuc(void) 9 { 10 cout << "fuc函数! "; 11 Copy_construction A; 12 return A; 13 } 14 15 16 /********返回类型为指针或者引用不会调用拷贝构造函数*********/
test5:
改变接匿名对象的方式:
1 #include<iostream> 2 using namespace std; 3 class Copy_construction { 4 public: 5 Copy_construction(int a = 0) 6 { 7 this->a = a; 8 cout << "这是有默认参数的构造函数! "; 9 } 10 Copy_construction(const Copy_construction &obj) 11 { 12 cout << "这是拷贝构造函数! "; 13 a = obj.a; 14 } 15 ~Copy_construction() 16 { 17 cout << "一个对象被析构了! "; 18 } 19 private: 20 int a; 21 }; 22 Copy_construction fuc(void) 23 { 24 cout << "fuc函数! "; 25 Copy_construction A; 26 return A;//调用拷贝构造函数,产生匿名对象 27 }//析构对象A,根据下面代码的接匿名对象的方式, 28 //此时匿名对象不仅不会马上析构,还会转正成为对象B 29 //从c++设计哲学上来说,这也是提高效率的一种方式,这样的设计是合理的,因为你想创建对象B,我就不用再新开辟内存了,直接用之前的匿名对象代替 30 void play_empty(void) 31 { 32 Copy_construction B=fuc();//这里不会调用拷贝构造函数,匿名对象直接转正了 33 cout << "匿名对象转正! "; 34 } 35 int main() 36 { 37 play_empty(); 38 39 cout << "hello world! "; 40 return 0; 41 }
test6:
再改变接匿名对象的方式,重写play_empty()函数:
void play_empty(void) { Copy_construction B; B= fuc(); cout << "匿名对象不会转正! "; } //如上所示代码,此时对象B会开辟内存,在用返回的匿名对象赋值给B,将会在赋值完成之后立即析构匿名对象,这个时候匿名对象不会转正。
summary:以下情况会调用拷贝构造函数
1.直接初始化和拷贝初始化时
2.将一个对象作为实参传递给一个非引用或非指针类型的形参时
3.从一个返回类型为非引用或非指针的函数返回一个对象时
4.用花括号列表初始化一个数组的元素或者一个聚合类(很少使用)中的成员时。