zoukankan      html  css  js  c++  java
  • C++拷贝构造函数的调用时机

    一、拷贝构造函数调用的时机

    ​ 当以拷贝的方式初始化对象时会调用拷贝构造函数,这里需要注意两个关键点,分别是以拷贝的方式初始化对象

    1. 初始化对象

    初始化对象是指,为对象分配内存后第一次向内存中填充数据,这个过程会调用构造函数,对象被创建后必须立即初始化。也就是说只要创建对象就会调用构造函数。

    2.初始化和赋值的区别

    初始化和赋值都是将数据写入内存中,从表面看,初始化在很多时候都是以复制的方式来实现的,很容易引起混淆。在定义的同时进行复制叫做初始化,定义完成以后再赋值(不管定义的时候有没有赋值)就叫做赋值。初始化只能由一次,赋值可以由很多次。具体可以看下面的示例。

    int a = 100;  //以赋值的方式初始化
    a = 200;  //赋值
    a = 300;  //赋值
    int b;  //默认初始化
    b = 29;  //赋值
    b = 39;  //赋值
    

    ​ 对于基本的数据类型,我们很少会区分初始化和赋值,即使是混淆了,也不会出现什么错误。但是对于类,他们的区别就非常重要了,因为初始化时会调用构造函数(以拷贝的方式初始化时会调用拷贝构造函数),而赋值时会调用重载过的赋值运算符。

    二、拷贝构造函数和普通构造函数调用的例子

    #include<iostream>
    #include<string>
    
    using namespace std;
    
    class Student {
    public:
    	Student(string name = "", int age = 0); //普通构造函数
    	Student(const Student &Stu); //拷贝构造函数
    	Student& operator=(const Student &Stu); // 重载 = 运算符
    	void display();
    	
    
    private:
    	string m_name;
    	int m_age;
    
    };
    
    //普通构造函数
    Student::Student(string name , int age )
    {
    	m_name = name;
    	m_age = age;
    }
    
    //拷贝构造函数
    Student::Student(const Student &Stu)
    {
    	this->m_name = Stu.m_name;
    	this->m_age = Stu.m_age;
    
    	cout << "Copy constructor was called." << endl;
    }
    
    // 重载 = 运算符
    Student& Student:: operator=(const Student &Stu)
    {
    	this->m_name = Stu.m_name;
    	this->m_age = Stu.m_age;
    
    	cout << "operator=() was called." << endl;
    
    	return *this;
    }
    
    void Student::display()
    {
    	cout << m_age << "  " << m_age << endl;
    }
    
    
    int main()
    {
    	Student stu1("Xiao Ming", 18);  // 调用普通构造函数
    	Student stu2("Xiao Wang", 18);  // 调用普通构造函数
    
    	Student stu3 = stu1;  // 调用拷贝构造函数
    	stu3 = stu2;  //调用operator=()
    
    	Student stu4(stu1);   // 调用拷贝构造函数
    
    	Student stu5; // 调用普通构造函数
    	stu5 = stu2;  //调用operator=()
    
    	return 0;
    }
    
    /*
    输出:
    	Copy constructor was called.
    	operator=() was called.
    	Copy constructor was called.
    	operator=() was called.
    
    
    */
    

    三、以拷贝的方式初始化对象

    1. 初始化对象时会调用构造函数,不同的初始化方式会调用不同的构造函数:
    • 如果用传递进来的实参初始化对象,那么会调用普通的构造函数。
    • 如果用现有对象的数据来初始化对象,就会调用拷贝构造函数,这就是以拷贝的方式初始化对象。
    2. 以拷贝的方式来初始化对象的几种情况:
    1. 将其它对象作为实参。

      Student stu1("Xiao Ming", 18);  // 普通初始化
      Student stu4(stu1);   // 以拷贝的方式进行初始化
      /* 即使我们不在类中显示定义拷贝构造函数,这种初始化方式也是有效的,编译器会生成默认的拷贝构造函数 */
      
    2. 在创建对象的同时赋值。

      Student stu1("Xiao Ming", 18);  // 普通初始化
      Student stu3 = stu1;  // 以拷贝的方式进行初始化
      /* 这是最常见的一种以拷贝的方式初始化对象的情况 */
      
    3. 函数的形参为类类型。

      如果函数的形参为类类型(对象),那么调用函数时要将另外一个对象作为实参传递进来赋值给形参,这也是以拷贝的方式初始化形参对象,如下所示。

      void func(Student s){
          //TODO:
      }
      Student stu1("Xiao Ming", 18);  // 普通初始化
      func(stu1);  //以拷贝的方式初始化
      
      /* func() 函数有一个 Student 类型的形参 s,将实参 stu 传递给形参 s 就是以拷贝的方式初始化的过程。 */
      
    4. 函数返回值为类类型(与编译器有关不绝对)

      ​ 当函数的返回值为类类型时,return 语句会返回一个对象,不过为了防止局部对象被销毁,也为了防止通过返回值修改原来的局部对象,编译器并不会直接返回这个对象,而是根据这个对象先创建出一个临时对象(匿名对象),再将这个临时对象返回。而创建临时对象的过程,就是以拷贝的方式进行的,会调用拷贝构造函数,如下所示。

      Student func(){
         Student stu1("Xiao Ming", 18);  // 普通初始化
          return stu1;
      }
      Student stu = func();
      
  • 相关阅读:
    开源APM应用性能管理工具调研
    Inside ARC — to see the code inserted by the compiler
    报表应用系统中怎样正确使用图表功能
    创建cifs系统案例之“实现将Windows磁盘共享至Linux”
    Eclipse快捷键 10个最有用的快捷键
    如何生成KeyStore
    android中调用系统的发送短信、发送邮件、打电话功能
    android自带theme
    Android 报错:Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
    Android oncreate onupgrade什么时候被调用
  • 原文地址:https://www.cnblogs.com/ay-a/p/10415808.html
Copyright © 2011-2022 走看看