精华内容
下载资源
问答
  • c++拷贝构造函数调用
    千次阅读 多人点赞
    2017-07-28 17:41:59

    拷贝构造函数调用的几种情况:

    1. 当用类的一个对象去初始化该类的另一个对象(或引用)时系统自动调用拷贝构造函数实现拷贝赋值。
    2. 若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。(这里可有可能被编译器优化)
    3. 当函数的返回值是类对象时,系统自动调用拷贝构造函数。(注意会有编译器可能会进行优化,而观察不到拷贝的发生)
    #include<ctime>
    #include<cstdlib>
    #include<iterator>
    #include<algorithm>
    #include<iostream>
    #include<numeric>
    using namespace std;
    
    class A {
    public:
    	A():data(0){}
    	A(const A& a){
    		data = a.data;
    		cout << "拷贝构造函数调用\n";
    	}
    	A& operator=(const A&a){
    		data = a.data;
    		cout << "调用赋值函数\n";
    		return *this;
    	}
    
    	int data;
    };
    
    void fun1(A a) {
    	return ;
    }
    
    A fun2() {
    	A a;
    	return a;
    }
    
    int main() {
    	A a;
    	A b(a);          //用类的一个对象a去初始化另一个对象b
    	A c = a;         //用类的一个对象a去初始化另一个对象c,注意这里是初始化,不是赋值
    	fun1(a);         //形参为类对象,实参初始化形参,调用拷贝构造函数。
    	A d = fun2();    //函数返回一个类对象时, 这里可能会被编译器优化,从而可能没有调用拷贝构造
    	d = a;           //d已经初始化过了,这里是赋值,调用赋值函数
    
    	return 0;
    }
    

    需要注意,在第三条:当函数的返回值是类对象时,系统自动调用拷贝构造函数。这里默认情况下一般会被编译器优化,减少不必要的拷贝构造,所以,具体的返回值可能会因编译器及编译选项的不同而不同。使用g++编译器,关闭优化g++ xxx.cpp -fno-elide-constructors后执行结果如下(-fno-elide-constructors选项就是用来关闭拷贝优化的):

    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    调用赋值函数
    

    默认情况下,优化后的结果如下:

    拷贝构造函数调用
    拷贝构造函数调用
    拷贝构造函数调用
    调用赋值函数
    

    编译器具体是怎么优化的,一般编译器会先看支不支持拷贝优化,如果不支持,再看有没有定义移动构造函数,如果都没有,就调用拷贝构造函数。更具体的细节可以参考移动语义及拷贝优化的内容。

    最后,注意A c=a;d=a;的不同,一个是初始化,一个是赋值。

    更多相关内容
  • 1.什么是拷贝构造函数拷贝构造函数嘛,当然就是拷贝和构造了。(其实很多名字,只要静下心来想一想,就真的是顾名思义呀)拷贝又称复制,因此拷贝构造函数又称复制构造函数。百度百科上是这样说的:拷贝构造函数...
  • 本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数、什么情况下调用赋值运算符。最后,简单的分析了下深拷贝和浅拷贝的问题。有需要的朋友可以看下
  • 原因:如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。...
  • C++拷贝构造函数(复制构造函数)详解 拷贝和复制是一个意思,对应的英文单词都是copy。对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word ...

    C++拷贝构造函数(复制构造函数)详解

    拷贝和复制是一个意思,对应的英文单词都是copy。对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。

    在 C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。

    严格来说,对象的创建包括两个阶段,首先要分配内存空间,然后再进行初始化:

    分配内存很好理解,就是在堆区、栈区或者全局数据区留出足够多的字节。这个时候的内存还比较“原始”,没有被“教化”,它所包含的数据一般是零值或者随机值,没有实际的意义。

    初始化就是首次对内存赋值,让它的数据有意义。注意是首次赋值,再次赋值不叫初始化。初始化的时候还可以为对象分配其他的资源(打开文件、连接网络、动态分配内存等),或者提前进行一些计算(根据价格和数量计算出总价、根据长度和宽度计算出矩形的面积等)等。说白了,初始化就是调用构造函数。

    很明显,这里所说的拷贝是在初始化阶段进行的,也就是用其它对象的数据来初始化新对象的内存。

    那么,如何用拷贝的方式来初始化一个对象呢?其实这样的例子比比皆是,string 类就是一个典型的例子。

    #include <iostream>
    #include <string>
    using namespace std;
    void func(string str){
        cout<<str<<endl;
    }
    int main(){
        string s1 = "http://c.ttt.net";
        string s2(s1);
        string s3 = s1;
        string s4 = s1 + " " + s2;
        func(s1);
        cout<<s1<<endl<<s2<<endl<<s3<<endl<<s4<<endl;
       
        return 0;
    }
    运行结果:
    http://c.ttt.net
    http://c.ttt.net
    http://c.ttt.net
    http://c.ttt.net
    http://c.ttt.net http://c.ttt.net
    

    s1、s2、s3、s4 以及 func() 的形参 str,都是使用拷贝的方式来初始化的。
    对于 s1,表面上看起来是将一个字符串直接赋值给了 s1,实际上在内部进行了类型转换,将 const char * 类型转换为 string 类型后才赋值的。s4 也是类似的道理。

    对于 s1、s2、s3、s4,都是将其它对象的数据拷贝给当前对象,以完成当前对象的初始化。

    对于 func() 的形参 str,其实在定义时就为它分配了内存,但是此时并没有初始化,只有等到调用 func() 时,才会将其它对象的数据拷贝给 str 以完成初始化。

    当以拷贝的方式初始化一个对象时,会调用一个特殊的构造函数,就是拷贝构造函数(Copy Constructor)。

    下面的例子演示了拷贝构造函数的定义和使用:

    #include <iostream>
    #include <string>
    using namespace std;
    class Student{
    public:
        Student(string name = "", int age = 0, float score = 0.0f);  //普通构造函数
        Student(const Student &stu);  //拷贝构造函数(声明)
    public:
        void display();
    private:
        string m_name;
        int m_age;
        float m_score;
    };
    Student::Student(string name, int age, float score): m_name(name), m_age(age), m_score(score){ }
    //拷贝构造函数(定义)
    Student::Student(const Student &stu){
        this->m_name = stu.m_name;
        this->m_age = stu.m_age;
        this->m_score = stu.m_score;
       
        cout<<"Copy constructor was called."<<endl;
    }
    void Student::display(){
        cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
    }
    int main(){
        Student stu1("小明", 16, 90.5);
        Student stu2 = stu1;  //调用拷贝构造函数
        Student stu3(stu1);  //调用拷贝构造函数
        stu1.display();
        stu2.display();
        stu3.display();
       
        return 0;
    }
    

    运行结果:

    Copy constructor was called.
    Copy constructor was called.
    小明的年龄是16,成绩是90.5
    小明的年龄是16,成绩是90.5
    小明的年龄是16,成绩是90.5
    

    第 8 行是拷贝构造函数的声明,第 20 行是拷贝构造函数的定义。拷贝构造函数只有一个参数,它的类型是当前类的引用,而且一般都是 const 引用。

    1) 为什么必须是当前类的引用呢?

    如果拷贝构造函数的参数不是当前类的引用,而是当前类的对象,那么在调用拷贝构造函数时,会将另外一个对象直接传递给形参,这本身就是一次拷贝,会再次调用拷贝构造函数,然后又将一个对象直接传递给了形参,将继续调用拷贝构造函数……这个过程会一直持续下去,没有尽头,陷入死循环。

    只有当参数是当前类的引用时,才不会导致再次调用拷贝构造函数,这不仅是逻辑上的要求,也是 C++ 语法的要求。

    2) 为什么是 const 引用呢?

    拷贝构造函数的目的是用其它对象的数据来初始化当前对象,并没有期望更改其它对象的数据,添加 const 限制后,这个含义更加明确了。

    另外一个原因是,添加 const 限制后,可以将 const 对象和非 const 对象传递给形参了,因为非 const 类型可以转换为 const 类型。如果没有 const 限制,就不能将 const 对象传递给形参,因为 const 类型不能转换为非 const 类型,这就意味着,不能使用 const 对象来初始化当前对象了。

    以上面的 Student 类为例,将 const 去掉后,拷贝构造函数的原型变为:
    Student::Student(Student &stu);

    此时,下面的代码就会发生错误:

    const Student stu1("小明", 16, 90.5);
    Student stu2 = stu1;
    Student stu3(stu1);
    

    stu1 是 const 类型,在初始化 stu2、stu3 时,编译器希望调用Student::Student(const Student &stu),但是这个函数却不存在,又不能将 const Student 类型转换为 Student 类型去调用Student::Student(Student &stu),所以最终调用失败了。

    当然,你也可以再添加一个参数为 const 引用的拷贝构造函数,这样就不会出错了。换句话说,一个类可以同时存在两个拷贝构造函数,一个函数的参数为 const 引用,另一个函数的参数为非 const 引用。

    默认拷贝构造函数

    在前面的教程中,我们还没有讲解拷贝构造函数,但是却已经在使用拷贝的方式创建对象了,并且也没有引发什么错误。这是因为,如果程序员没有显式地定义拷贝构造函数,那么编译器会自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数很简单,就是使用“老对象”的成员变量对“新对象”的成员变量进行一一赋值,和上面 Student 类的拷贝构造函数非常类似。

    对于简单的类,默认拷贝构造函数一般是够用的,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,如动态分配的内存、打开的文件、指向其他数据的指针、网络连接等,默认拷贝构造函数就不能拷贝这些资源,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。

    展开全文
  • 拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝
  • C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法。下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象时,它...
  • C++拷贝构造函数的四种调用方式

    千次阅读 2020-06-21 22:31:59
    代码拿着跑一跑就什么都知道了 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> using namespace std;... 构造函数 */ Student(int age, string name) { this->age.

    代码

    #define _CRT_SECURE_NO_WARNINGS
    #include<iostream>
    #include<string>
    using namespace std;
    static int i = 0;
    class Student
    {
    private:
    	int age;
    	string name;
    public:
    	/*
    	构造函数
    	*/
    	Student(int age, string name)
    	{
    		this->age = age;
    		this->name = name;
    
    		cout << "构造函数" << endl;
    	}
    	/*
    	无参构造函数
    	*/
    	Student() { cout << "无参构造函数" << endl; }
    	/*
    	拷贝构造函数
    	*/
    	Student(const Student & stur)
    	{
    		age = stur.age;
    		name = stur.name;
    		cout << "拷贝构造函数" << endl;
    	}
    	/*
    	析构函数
    	*/
    	~Student()
    	{
    		cout << "析构函数" << endl;
    
    	}
    	void print()
    	{
    		cout << age << endl;
    	}
    };
    
    Student fun(int age, string name)
    {
    	Student stu(age, name);   // stu是局部变量,在函数执行完将会进行析构
    	return stu;//会存在Student temp = stu,在主调函数中如果有变量接受  temp的话就不会立刻释放
    }
    
    void fun2(const Student stur)
    {
    	cout << "fun2" << endl;
    }
    
    
    return 0;
    }
    

    四种调用方法

    int main()
    {
    	Student stu1(12,"lisi");
    
    #if 0
    	//第一种调用方式
    	Student stu2(stu1);
    
    	//第二种
    	Student stu3 = stu1;
    
    	//注:以下方式不行
    	 Student stu3;
    	 stu3 = stu1;// 这是先调用无参构造创建,然后再赋值
    #endif
    	//第三种作为函数的返回值时会存在  Student temp = stu;
    	fun(10, "张三");
    	cout << "fun执行完了" << endl;//temp在此之前被析构,相当于匿名对象,使用完就会被析构
    
    #if 0
    	Student stu4 = fun(11, "王五");//这种情况  stu4= 这一过程没有调用拷贝构造函数,而是直接将temp转正为stu4
    	cout << "fun执行完了" << endl;//temp被转正为stu4
    
    	//第四种,作为函数参数使用时
    	fun2(stu1);//存在Student stur = stu1
    
    #endif
    	

    运行结果

    方式1与2

    方式3  不用变量接收,执行完以后临时对象立刻被析构

     

    方式3  使用变量接受,临时对象转正

    方式4  存在Student stur = stu1

    展开全文
  • C++中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。 严格来说,对象的创建包括两个阶段..

    拷贝和复制是一个意思,对应的英文单词都是copy。对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。

    在 C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对象创建出一个新的对象。从本质上讲,对象也是一份数据,因为它会占用内存。

    严格来说,对象的创建包括两个阶段,首先要分配内存空间,然后再进行初始化:

    分配内存很好理解,就是在堆区、栈区或者全局数据区留出足够多的字节。这个时候的内存还比较“原始”,没有被“教化”,它所包含的数据一般是零值或者随机值,没有实际的意义。

    初始化就是首次对内存赋值,让它的数据有意义。注意是首次赋值,再次赋值不叫初始化。初始化的时候还可以为对象分配其他的资源(打开文件、连接网络、动态分配内存等),或者提前进行一些计算(根据价格和数量计算出总价、根据长度和宽度计算出矩形的面积等)等。说白了,初始化就是调用构造函数。

    很明显,这里所说的拷贝是在初始化阶段进行的,也就是用其它对象的数据来初始化新对象的内存。

    那么,如何用拷贝的方式来初始化一个对象呢?其实这样的例子比比皆是,string 类就是一个典型的例子。

     

    运行结果:

    http://c.biancheng.net

    http://c.biancheng.net

    http://c.biancheng.net

    http://c.biancheng.net

    http://c.biancheng.net http://c.biancheng.net

    s1、s2、s3、s4 以及 func() 的形参 str,都是使用拷贝的方式来初始化的。

    对于 s1,表面上看起来是将一个字符串直接赋值给了 s1,实际上在内部进行了类型转换,将 const char * 类型转换为 string 类型后才赋值的。

    对于 s1、s2、s3、s4,都是将其它对象的数据拷贝给当前对象,以完成当前对象的初始化。

    对于 func() 的形参 str,其实在定义时就为它分配了内存,但是此时并没有初始化,只有等到调用 func() 时,才会将其它对象的数据拷贝给 str 以完成初始化。

    当以拷贝的方式初始化一个对象时,会调用一个特殊的构造函数,就是拷贝构造函数(Copy Constructor)。

    下面的例子演示了拷贝构造函数的定义和使用:

     

    运行结果:

    Copy constructor was called.

    Copy constructor was called.

    小明的年龄是16,成绩是90.5

    小明的年龄是16,成绩是90.5

    小明的年龄是16,成绩是90.5

    第 8 行是拷贝构造函数的声明,第 20 行是拷贝构造函数的定义。拷贝构造函数只有一个参数,它的类型是当前类的引用,而且一般都是 const 引用。

    1) 为什么必须是当前类的引用呢?

    如果拷贝构造函数的参数不是当前类的引用,而是当前类的对象,那么在调用拷贝构造函数时,会将另外一个对象直接传递给形参,这本身就是一次拷贝,会再次调用拷贝构造函数,然后又将一个对象直接传递给了形参,将继续调用拷贝构造函数……这个过程会一直持续下去,没有尽头,陷入死循环。

    只有当参数是当前类的引用时,才不会导致再次调用拷贝构造函数,这不仅是逻辑上的要求,也是 C++ 语法的要求。

    2) 为什么是 const 引用呢?

    拷贝构造函数的目的是用其它对象的数据来初始化当前对象,并没有期望更改其它对象的数据,添加 const 限制后,这个含义更加明确了。

    另外一个原因是,添加 const 限制后,可以将 const 对象和非 const 对象传递给形参了,因为非 const 类型可以转换为 const 类型。如果没有 const 限制,就不能将 const 对象传递给形参,因为 const 类型不能转换为非 const 类型,这就意味着,不能使用 const 对象来初始化当前对象了。

    以上面的 Student 类为例,将 const 去掉后,拷贝构造函数的原型变为:

    Student::Student(Student &stu);

    此时,下面的代码就会发生错误:

     

    stu1 是 const 类型,在初始化 stu2、stu3 时,编译器希望调用Student::Student(const Student &stu),但是这个函数却不存在,又不能将 const Student 类型转换为 Student 类型去调用Student::Student(Student &stu),所以最终调用失败了。

    当然,你也可以再添加一个参数为 const 引用的拷贝构造函数,这样就不会出错了。换句话说,一个类可以同时存在两个拷贝构造函数,一个函数的参数为 const 引用,另一个函数的参数为非 const 引用。

    默认拷贝构造函数

    在前面的教程中,我们还没有讲解拷贝构造函数,但是却已经在使用拷贝的方式创建对象了,并且也没有引发什么错误。这是因为,如果程序员没有显式地定义拷贝构造函数,那么编译器会自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数很简单,就是使用“老对象”的成员变量对“新对象”的成员变量进行一一赋值,和上面 Student 类的拷贝构造函数非常类似。

    编程学习:

     

     

    展开全文
  • 详解C++ 拷贝构造函数

    2020-08-18 21:20:31
    主要介绍了C++ 拷贝构造函数的相关资料,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
  • 定义一个类 #include <iostream> using namespace std;... "这是无参构造函数: m_a=" << m_a << ",m_b=" << m_b << endl<<endl; } MyClass(int a, int b) { m_a = a
  • C++拷贝构造函数调用时机及陷阱

    千次阅读 2018-06-28 12:01:41
    拷贝构造调用有四种 用一个对象 初始化 另一个对象时 函数实参传递给形参时,这也差不多是初始化啦 函数返回值,C++编译器在这做的就很奇怪了,今天早上调了一早上 #define _CRT_SECURE_NO_WARNINGS #include &...
  • 构造函数可以有多个,而拷贝构造函数只能有一个,因为拷贝构造函数的参数只能是当前类的一个对象,参数表是固定的,无法重载,若用户没有定义自己的辅助构造函数,系统会自动生成一个复制构造函数(浅拷贝构造函数,...
  • 本篇文章是对C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程进行了总结与分析,需要的朋友参考下
  • C++ 拷贝构造函数详解

    千次阅读 2021-06-14 15:24:36
    C++ 拷贝构造函数详解 下面的讲解将以C++标准库的string类作为讲解对象,string类:class with pointer member(s) 1、拷贝构造函数和拷贝赋值函数 1.1引入 下面是给出的测试函数,也是我们要能在自己设计的myString...
  • C++拷贝构造函数调用时机

    千次阅读 多人点赞 2022-04-14 17:30:22
    本章内容:C++拷贝构造函数调用时机是?什么时候会调用拷贝构造函数
  • 三种情况如下: 1.对象作为函数参数,以值传递的方式传入函数体。 2.对象作为函数返回值,以值传递的方式从函数反回。...Play(5) 调用了构造函数2 和 一次拷贝构造函数和,编译时先把 实参5 通过传参给 Pl...
  •  当一个类对象以另一个同类实体作为初值时,大部分情况下会调用拷贝构造函数。 一般是这三种具体情况:  显式地以一个类对象作为另一个类对象的初值,形如X xx=x;  当类对象被作为参数交给函数时。  当函数...
  • 一次在ReturnRvalue()函数中,构造好了Copyable对象,返回的时候会调用拷贝构造函数生成一个临时对象,在调用AcceptVal()时,又会将这个对象拷贝给函数的局部变量a,一共调用了两次拷贝构造函数。而AcceptRef()的...
  • C++——拷贝构造函数

    千次阅读 2022-05-18 23:50:28
    一、什么是拷贝构造函数 二、如何进行拷贝 实现缺省的拷贝构造函数 三、拷贝构造函数的使用 //c自动添加缺省构造函数。。。6个,c11新增两个 //拷贝构造函数不能够。。。 系统调动 //当一个对象初始化另一个...
  • C++ 拷贝构造函数和赋值构造函数

    万次阅读 多人点赞 2019-04-06 16:43:35
    C++中复制控制是一个比较重要的话题,主要包括复制构造函数、重载赋值操作符、析构函数这三部分,这三个函数是一致的,如果类需要析构函数,则它也需要复制操作符 和 复制构造函数,这个规则被称为 C++的“三法则...
  • C++ 拷贝构造函数与赋值函数

    千次阅读 2019-02-20 14:09:46
    这里我们用类String 来介绍这两个函数: ...试想一下,假如形参是该类的一个实例,由于是传值参数,我们把形参复制到实参会调用拷贝构造函数,如果允许拷贝构造函数传值,就会在拷贝构造函数调用拷贝构...
  • 主要介绍了C++类继承之子类调用父类的构造函数的实例详解的相关资料,希望通过本文大家能够掌握C++类继承的相关知识,需要的朋友可以参考下
  • c++拷贝构造函数详解

    2020-04-17 16:09:59
    c++拷贝构造函数详解 一、什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量...
  • 主要介绍了c/c++拷贝构造函数和关键字explicit的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 一. 什么是拷贝构造函数 转自百度定义:拷贝构造函数,又称复制构造函数,是一种...拷贝构造函数调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。 对于普...
  • 什么时候调用拷贝构造函数   1. 调用函数时,实参是对象,形参不是引用类型 如果函数的形参是引用类型,就不会调用拷贝构造函数 #include "Human.h" using namespace std; //函数传值,会自动调用拷贝构造...
  • 构造函数的执行次序如下: ...1,调用基类构造函数调用顺序按照他们的继承时声明的顺序。 2,调用内嵌成员对象的构造函数调用顺序按照他们在类中声明的 顺序。 3,派生类的构造函数体中的内容。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 116,890
精华内容 46,756
关键字:

c++拷贝构造函数调用

c++ 订阅