C++什么时候调用拷贝构造函数和什么时候调用构造函数

拷贝构造函数 都是在什么情况下调用???

/*
 **
     什么时候调用拷贝构造函数
 **
 */

#include <iostream>
using namespace std;

//日期类
class Date{

public:
    int year,month,day;
    Date(){//无参构造
        cout << "日期类的构造函数" << endl;
    }

    ~Date(){
        cout << "日期的析构函数" << endl;
    }

#pragma 拷贝构造函数里面的参数类型必须是引用
    Date (const Date& d3){
        this->year = d3.year;
        this->month = d3.month;
        this->day = d3.day;
        cout << "拷贝构造函数Date (Date& d3)" << endl;

    }

};

void fa(Date d){//在这个参数可以看出会创建一个新的临时变量d对象,相当于Date d = d;后面的d是传进来的,也就是通过相同类型对象来创建对象,所以这里会调用拷贝构造函数。

}

//主函数
int main(){
    Date d;
    cout << "===== 1 =====" << endl;

    fa(d);

    cout << "===== 2 =====" << endl;
    return 0;
}

运行结果:

日期类的构造函数
===== 1 =====
拷贝构造函数Date (Date& d3)   //fa函数进栈
日期的析构函数                 //弹栈
===== 2 =====
日期的析构函数
Program ended with exit code: 0

再写一个参数是引用类型的函数 fb 如下:

void fb(Date &d){ //这里是给传进的参数创建别名(引用)不会创建新的对象

}

修改主函数如下:

/主函数
int main(){
    Date d;
    cout << "===== 1 =====" << endl;

    fa(d);

    cout << "===== 2 =====" << endl;

    fb(d);
    cout << "===== 3 =====" << endl;
    return 0;
}

运行结果可以看出在2和3之间并没有创建新的对象

日期类的构造函数
===== 1 =====
拷贝构造函数Date (Date& d3)
日期的析构函数
===== 2 =====
===== 3 =====
日期的析构函数
Program ended with exit code: 0

再创建一个参数类型是指针类型的函数 fc 如下:

void fc(Date *d){ //传进来的参数是指针类型
    //这里创建了一个指针变量放在栈里面了,但是没有创建新的对象,指针指向的是传进来的对象的地址
}

主函数如下:

//主函数
int main(){
    Date d;
    cout << "===== 1 =====" << endl;

    fa(d);

    cout << "===== 2 =====" << endl;

    fb(d);
    cout << "===== 3 =====" << endl;
    fc(&d);
    cout << "===== 4 =====" << endl;
    return 0;
}

运行的结果如下:

日期类的构造函数
===== 1 =====
拷贝构造函数Date (Date& d3)
日期的析构函数
===== 2 =====
===== 3 =====
===== 4 =====
日期的析构函数

从运行结果3和4之间也可以知道并没有创建新的对象。

再来,创建一个返回值类型是Date ,参数是引用类型的函数 fd 如下:

Date fd(Date &r){
    return r;
}

主函数中:

//主函数
int main(){
    Date d;
    cout << "===== 1 =====" << endl;
    fa(d);
    cout << "===== 2 =====" << endl;
    fb(d);
    cout << "===== 3 =====" << endl;
    fc(&d);
    cout << "===== 4 =====" << endl;
    fd(d);
    cout << "===== 5 =====" << endl;

    return 0;
}

运行结果如下:

日期类的构造函数
===== 1 =====
拷贝构造函数Date (Date& d3)
日期的析构函数
===== 2 =====
===== 3 =====
===== 4 =====
拷贝构造函数Date (Date& d3)
日期的析构函数
===== 5 =====
日期的析构函数
Program ended with exit code: 0

从运行结果可知在4和5之间调用了拷贝构造函数创建对象了。那fd这个函数哪里创建对象了呢?  参数是引用类型,只是起别名,所以并没有创建对象。是返回值这里创建了,返回值类型是Date类型,相当于通过引用 Date = r ;创建了一个匿名的临时对象,所以这里会调用拷贝构造函数。

如果main主函数中修改如下,结果会如何呢?

    cout << "===== 4 =====" << endl;
    Date d2 = fd(d);
    cout << "===== 5 =====" << endl;
    

理论上fd(d); 这里有一个拷贝构造函数和一个析构函数  还有这一步Date d2 = fd(d);  这里应该还有一个拷贝构造函数

运行结果如下:

日期类的构造函数
===== 1 =====
拷贝构造函数Date (Date& d3)
日期的析构函数
===== 2 =====
===== 3 =====
===== 4 =====
拷贝构造函数Date (Date& d3)
===== 5 =====
日期的析构函数
日期的析构函数
Program ended with exit code: 0

为什么运行结果和我们分析的理论不一样呢??45之间为什么不是2个拷贝构造函数和1个析构函数呢?(其中一个拷贝构造函数和析构函数是fd的返回值临时变量的)

那是因为编译器做的优化,它把那个临时变量的拷贝构造函数和析构函数相抵消了,所以这里也就只显示了 Date d2 = ...这个的拷贝构造函数。

再写一个返回值是引用类型  参数是引用类型的函数 fe:

Date& fe(Date &r){
    return r;
}

主函数中添加如下代码:

    <p class="p1"><span class="s1">    cout</span><span class="s2"> << </span><span class="s3">"===== 5 ====="</span><span class="s2"> << </span><span class="s4">endl</span><span class="s2">;</span></p><p class="p2"><span class="s5">    </span><span class="s6">fe</span><span class="s5">(d);</span><span class="s7">//</span><span class="s3">参数</span><span class="s7"> </span><span class="s3">返回值都是引用类型的函数</span></p><p class="p1"><span class="s2">    </span><span class="s1">cout</span><span class="s2"> << </span><span class="s3">"===== 6 ====="</span><span class="s2"> << </span><span class="s4">endl</span><span class="s2">;</span></p><p class="p3"><span class="s3">    </span><span class="s8">Date</span><span class="s3"> d3 = </span><span class="s9">fe</span><span class="s3">(d);</span></p><p class="p1"><span class="s2">    </span><span class="s1">cout</span><span class="s2"> << </span><span class="s3">"===== 7 ====="</span><span class="s2"> << </span><span class="s4">endl</span><span class="s2">;</span></p><p class="p1"><span class="s1">    Date</span><span class="s2"> &d4 = </span><span class="s3">fe</span><span class="s2">(d);  //创建一个引用变量接收函数返回的</span></p><p class="p2"><span class="s4">    </span><span class="s5">cout</span><span class="s4"> << </span><span class="s2">"===== 8 ====="</span><span class="s4"> << </span><span class="s6">endl</span><span class="s4">;</span></p>
    

运行结果如下:

日期类的构造函数
===== 1 =====
拷贝构造函数Date (Date& d3)
日期的析构函数
===== 2 =====
===== 3 =====
===== 4 =====
拷贝构造函数Date (Date& d3)
===== 5 =====
===== 6 =====
拷贝构造函数Date (Date& d3)
<p class="p1"><span class="s1">===== 7 =====</span></p><p class="p1"><span class="s1">===== 8 =====</span></p><p class="p2"><span class="s1">日期的析构函数</span></p><p class="p2"><span class="s1">日期的析构函数</span></p><p class="p2"><span class="s1">日期的析构函数</span></p><p class="p3"><span class="s1">Program ended with exit code: 0</span></p>

从运行结果可知56之间的只是调用函数fe  ,该函数的返回值和参数都是引用类型,并没有创建新的对象。

而在67之间因为通过返回值创建了对象 Date d3 =......这里调用了拷贝构造函数。

而78之间因为创建一个引用类型的变量来接收函数返回的,也就是相当于起别名,而并没有创建新对象,所以并没有调用拷贝构造函数

再来,在main函数当中添加如下代码:

    cout << "===== 8 =====" << endl;
    Date d5[2] = {d,d2};              //数组里面有2个元素,分别用d和d2来赋值
    <span class="s1" style="font-family: Arial, Helvetica, sans-serif;">cout</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> << </span><span class="s3" style="font-family: Arial, Helvetica, sans-serif;">"===== 9 ====="</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> << </span><span class="s4" style="font-family: Arial, Helvetica, sans-serif;">endl</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;">;</span><p class="p2"><span class="s3">    </span><span class="s5">Date</span><span class="s3"> d6[</span><span class="s6">5</span><span class="s3">];</span></p><p class="p1"><span class="s2">    </span><span class="s1">cout</span><span class="s2"> << </span><span class="s3">"===== 10 ====="</span><span class="s2"> << </span><span class="s4">endl</span><span class="s2">;</span></p>

运行结果如下:

<p class="p1"><span class="s1"><span style="font-size:18px;">日期类的构造函数</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 1 =====</span></span></p><p class="p2"><span style="font-size:18px;"><span class="s2">拷贝构造函数</span><span class="s1">Date (Date& d3)</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 2 =====</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 3 =====</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 4 =====</span></span></p><p class="p2"><span style="font-size:18px;"><span class="s2">拷贝构造函数</span><span class="s1">Date (Date& d3)</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 5 =====</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 6 =====</span></span></p><p class="p2"><span style="font-size:18px;"><span class="s2">拷贝构造函数</span><span class="s1">Date (Date& d3)</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 7 =====</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 8 =====</span></span></p><p class="p2"><span style="font-size:18px;"><span class="s2">拷贝构造函数</span><span class="s1">Date (Date& d3)</span></span></p><p class="p2"><span style="font-size:18px;"><span class="s2">拷贝构造函数</span><span class="s1">Date (Date& d3)</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 9 =====</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期类的构造函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期类的构造函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期类的构造函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期类的构造函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期类的构造函数</span></span></p><p class="p2"><span class="s1"><span style="font-size:18px;">===== 10 =====</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p1"><span class="s1"><span style="font-size:18px;">日期的析构函数</span></span></p><p class="p3"><span class="s1"><span style="font-size:18px;">Program ended with exit code: 0</span></span></p>

在结果89之间看到有2个拷贝构造函数。因为是通过同类型对象来创建对象的,所以会调用2个拷贝构造函数。

在9和10 之间会看到5个构造函数,这里不是拷贝构造而是直接创建对象,所以是构造函数。

如果再在main函数里面添加如下的代码:

<span style="font-size:24px;">    </span><span style="font-size:18px;"><span class="s1" style="font-family: Arial, Helvetica, sans-serif;">cout</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> << </span><span class="s3" style="font-family: Arial, Helvetica, sans-serif;">"===== 10 ====="</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;"> << </span><span class="s4" style="font-family: Arial, Helvetica, sans-serif;">endl</span><span class="s2" style="font-family: Arial, Helvetica, sans-serif;">;</span></span><p class="p2"><span style="font-size:18px;"><span class="s3">    d = d2;  </span><span class="s5">//</span><span class="s6">赋值操作</span></span></p><p class="p1"><span style="font-size:18px;"><span class="s2">    </span><span class="s1">cout</span><span class="s2"> << </span><span class="s3">"===== 11 ====="</span><span class="s2"> << </span><span class="s4">endl</span><span class="s2">;</span></span></p><p class="p2"><span style="font-size:18px;"><span class="s3">    </span><span class="s7">Date</span><span class="s3"> *d7 = </span><span class="s8">new</span><span class="s3"> </span><span class="s7">Date</span><span class="s3">;</span></span></p><p class="p2"><span style="font-size:18px;"><span class="s3"></span></span></p><p class="p1"><span style="font-size:18px;"><span class="s1">    delete</span><span class="s2"> d7;</span></span></p><p></p><p class="p1"><span style="font-size:18px;"><span class="s2">    </span><span class="s1">cout</span><span class="s2"> << </span><span class="s3">"===== 12 ====="</span><span class="s2"> << </span><span class="s4">endl</span><span class="s2">;</span></span></p>

运行结果:

<p class="p1"><span class="s1">===== 10 =====</span></p><p class="p1"><span class="s1">===== 11 =====</span></p><p class="p2"><span class="s1">日期类的构造函数</span></p><p class="p2"><span class="s1"></span></p><p class="p1"><span class="s1">日期的析构函数</span></p><p></p><p class="p1"><span class="s1">===== 12 =====</span></p>

运行结果10 和 11之间什么都没有打印,也就是并没有创建新的对象。

而11和12之间只有一个构造函数,Date *d7是指针,指向一个对象,在创建这个对象的时候就调用了构造函数。

如果把11和12当中 delete d7注释掉  然后通过d7来创建对象,main函数中增加如下代码呢:

   cout << "===== 12 =====" << endl;
    Date *d8 = new Date(*d7);
    delete d8;
    cout << "===== 13 =====" << endl;

运行结果如下:

<p class="p1"><span class="s1">===== 12 =====</span></p><p class="p1"><span class="s2">拷贝构造函数</span><span class="s1">Date (Date& d3)</span></p><p class="p2"><span class="s1">日期的析构函数</span></p><p class="p1"><span class="s1">===== 13 =====</span></p>

在12和13之间是通过*d7得到同类型的对象然后创建对象,所以这里会调用拷贝构造函数。

要搞明白:

什么时候调用构造函数 ?   什么时候调用拷贝构造函数 ?  什么时候什么都不调用??

时间: 2024-08-04 13:08:08

C++什么时候调用拷贝构造函数和什么时候调用构造函数的相关文章

C++类构造优化 - 不调用拷贝构造函数

假如有下面这样一个类: class A{ public: A(int p, char q):x(p), c(q){ cout << "constructor called" << endl; } A(const A& a){x = a.x; c = a.c; cout << "copy constructor called" << endl;} ~A(){cout << "destruct

以一个类成员函数来说明拷贝构造函数与析构函数何时调用

mystring operator +(const char *str, const mystring &it) { mystring stro; strcpy(stro.s, str); strcat(stro.s, it.s); printf("stro = %p\n", stro.s); return stro; } 当return stro时,其实返回的是stro的一个副本.这时就会调用拷贝构造函数.副本stro其实是在为外部使用作准备.会后于原始stro销毁. 接着,

拷贝构造函数和赋值运算符的调用情况

很多情况下,对于 如下的说明,很难接受 int a(10); 其实完全等价于int a=10; 所以下面的情况更加难以接受: class A;//定义class A 应用: A a; A b(a);//其实完全等价于A b=a,调用的都是拷贝构造函数,在所有人的眼中如果不是,非常熟悉这样赋值的方式,还真是看做是赋值运算. 例子如下: void Test(A a) { } 在这个函数中,通过值的传递,其实调用的是拷贝构造函数,而没有调用赋值运算符,或者默认的构造函数, class T { publ

拷贝构造函数和赋值运算符的调用时机

摘自:http://www.2cto.com/kf/201211/166530.html #include <iostream> using namespace std; class Fraction{  private:      int fenmu; //分母      int fenzi; //分子  public:      Fraction(int x,int y){          fenzi = x;          fenmu = y;      }      Fracti

利用无名对象初始化对象系统不会调用拷贝构造函数

#include <iostream> using namespace std; class Internet { public: Internet(char *name,char *address) { cout<<"载入构造函数"<<endl; strcpy(Internet::name,name); } Internet(Internet &temp) { cout<<"载入COPY构造函数"<&l

C++C++中构造函数与析构函数的调用顺序

http://blog.csdn.net/xw13106209/article/details/6899370 1.参考文献 参考1: C++继承中构造函数.析构函数调用顺序及虚函数的动态绑定 参考2: 构造函数.拷贝构造函数和析构函数的的调用时刻及调用顺序 参考3: C++构造函数与析构函数的调用顺序 2.构造函数.析构函数与拷贝构造函数介绍 2.1构造函数 构造函数不能有返回值 缺省构造函数时,系统将自动调用该缺省构造函数初始化对象,缺省构造函数会将所有数据成员都初始化为零或空 创建一个对象

构造函数的分类及调用

构造函数可以使用两种方式进行分类: 按参数分为:无参构造和有参构造 按类型分为:普通构造和拷贝构造 class Person { public: //无参构造(也可称为默认构造) Person() { cout << "Person的无参构造" << endl; } //有参构造 Person(int a) { age = a; cout << "Person的有参构造" << endl; } //拷贝构造函数 Per

构造函数的分类及调用(2)

两种分类方式: 1.按参数分为:有参构造和无参构造(默认构造) 2.按类型分为:普通构造和拷贝构造 三种调用方式: 1.括号法 2.显示法 3.隐式转换法 匿名对象的特点:特点:当前行执行结束后,系统会立即回收掉匿名对象 1 #include <iostream> 2 using namespace std; 3 4 class Person 5 { 6 public: 7 //构造函数 8 Person() 9 { 10 cout << "Person默认构造函数的调用

c++学习笔记5,多重继承中派生类的构造函数与析构函数的调用顺序(二)

现在来测试一下在多重继承,虚继承,MI继承中虚继承中构造函数的调用情况. 先来测试一些普通的多重继承.其实这个是显而易见的. 测试代码: //测试多重继承中派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace std; class base { public: base() { cout<<"base created!"<<endl; }