精华内容
下载资源
问答
  • 1.拷贝构造函数 首先,简单介绍一下拷贝构造函数。拷贝构造函数是构造函数的一种,它在创建对象时,是使用同一类中之前创建的对象来初始...拷贝构造函数的一般形式如下所示: ClassName(const ClassName& obj...

    目录

     

    1.拷贝构造函数

    2.浅拷贝和深拷贝

    3.拷贝构造函数的参数能用值传递吗?


    1.拷贝构造函数

    首先,简单介绍一下拷贝构造函数。拷贝构造函数是构造函数的一种,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。

    拷贝构造函数将创建好(已初始化)的对象作为参数,返回一个新的对象。

    如果我们没有定义拷贝构造函数,系统会自动生成一个默认的拷贝构造函数。

    拷贝构造函数的一般形式如下所示:

    ClassName(const ClassName& obj)
    {}

    我们呢来看一个实例:

    class  People
    {
    public:
    	//构造函数
    	People(int age, string name) :_age(age), _name(name)
    	{}
    //    拷贝构造函数
    	People(const People& obj)
    	{
    		_age = obj._age;
    		_name = obj._name;
    		cout << "拷贝构造调用" << endl;
    	}
    	void Print()
    	{
    		cout << _name << ":" << _age<< endl;
    	}
    private:
    	int _age;
    	string _name;
    };
    
    int main()
    {
    	People xiaoMing(14, "小明");
    	People xiaoHong(xiaoMing);
    	xiaoMing.Print();
    	xiaoHong.Print();
    	return 0;
    }
    

    打印结果如下:

    可以发现小明的属性已经拷贝给了小红,那么如果我们删除掉上述代码中的拷贝构造函数,结果会怎么样?答案是:结果是一样的,这是为什么呢,这是因为系统会生成一个默认的拷贝构造函数,来进行对象初始化对象的操作,但是这种拷贝构造函数只能用于浅拷贝,不能用于深拷贝。接下来我们引出浅拷贝和身拷贝。

    2.浅拷贝和深拷贝

    假设类中的成员变量有一个指针,我们在类的构造函种为这个指针在堆上申请了内存。如果我们用这个类取初始化其他类会发生什么情况?

    我们先来看一个实例:

    class  People
    {
    	public:
    	//构造函数
    		People(int age, string name, int size = 3) :_age(age), _name(name),_size(size)
    	{
    			_arr = new int[size];
    	}
    		~People()
    		{
    			delete[] _arr;
    		}
    	void Print()
    	{
    		cout << _name << ":" << _age<< endl;
    	}
    private:
    	int _age;
    	string _name;
    	int _size;
    	int* _arr;
    };
    
    int main()
    {
    	People xiaoMing(14, "小明");
    	People xiaoHong(xiaoMing);	
    	return 0;
    }

    我们在People类中加了两个变量,一个_size,一个int的指针,然后在析构函数种将_arr的内存释放。执行会发现上述代码会报错,这是为什么呢?

    如上图,小明首先在堆上有三个字节的大小,通过一个默认的拷贝构造函数(浅拷贝),小红的_arr指针也指向了这块空间,当程序结束的时候,首先调用小明的析构函数释放了这块空间,被释放掉了,小红的析构函数又取释放这块被释放掉的空间,所以程序会报错。

    总结一下:

    浅拷贝只是复制指向某些对象的指针,并不会对所指内容进行复制。如上:浅拷贝只是把小名的_arr指针指向了小明的_arr指针,并没又进行空间的赋值。当程序结束的时候,不同对象的析构函数会释放同一块内存,报错。

    而深拷贝,通过写拷贝构造函数,使堆上的空间也复制一份,当程序结束的时候,不同对象的析构函数会释放的内存虽然内容一样,但是地址不一样,所以不会报错。

    在上述的代码种我们增加拷贝构造函数如下之后,程序不会报错。

    People(const People& obj)
    {
    	_age = obj._age;
    	_name = obj._name;
    	_size = obj._size;
    	_arr = new int[_size];
    	cout << "拷贝构造调用" << endl;
    
    }

    3.拷贝构造函数的参数能用值传递吗?

    由函数的传参过程我们可以得知,如果函数的参数不是指针或者引用的时候,我们在传参的时候,会将实参复制给形参。

    如果我们将拷贝构造函数的参数去掉引用,那么在调用拷贝构造函数的时候,首先会申请一个新的对象,然后用传入的实参去初始化这个新的对象,这个时候还会调用到我们的拷贝构造函数,如此层层调用,形成无限的递归。

    因此,拷贝构造函数的参数必须用引用或者指针。

    展开全文
  • 复制构造函数

    2020-10-15 08:44:42
    复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。一个类中写两个复制构造函数...

    复制构造函数是构造函数的一种,也称拷贝构造函数,它只有一个参数,参数类型是本类的引用。

    复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。一个类中写两个复制构造函数,一个的参数是 const 引用,另一个的参数是非 const 引用,也是可以的。

    如果类的设计者不写复制构造函数,编译器就会自动生成复制构造函数。大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制,即使得目标对象的每个成员变量都变得和源对象相等。编译器自动生成的复制构造函数称为“默认复制构造函数”。

    注意,默认构造函数(即无参构造函数)不一定存在,但是复制构造函数总是会存在。

    下面是一个复制构造函数的例子。

    #include<iostream >
    using namespace std;
    class Complex
    {
    public:
        double real, imag;
        Complex(double r, double i) {
            real= r; imag = i;
        }
    };
    int main(){
        Complex cl(1, 2);
        Complex c2 (cl);  //用复制构造函数初始化c2
        cout<<c2.real<<","<<c2.imag;  //输出 1,2
        return 0;
    }
    

    第 13 行给出了初始化 c2 的参数,即 c1。只有编译器自动生成的那个默认复制构造函数的参数才能和 c1 匹配,因此,c2 就是以 c1 为参数,调用默认复制构造函数进行初始化的。初始化的结果是 c2 成为 c1 的复制品,即 c2 和 c1 每个成员变量的值都相等。

    如果编写了复制构造函数,则默认复制构造函数就不存在了。下面是一个非默认复制构造函数的例子。

    #include<iostream>
    using namespace std;
    class Complex{
    public:
        double real, imag;
        Complex(double r,double i){
            real = r; imag = i;
        }
        Complex(const Complex & c){
            real = c.real; imag = c.imag;
            cout<<"Copy Constructor called"<<endl ;
        }
    };
    
    int main(){
        Complex cl(1, 2);
        Complex c2 (cl);  //调用复制构造函数
        cout<<c2.real<<","<<c2.imag;
        return 0;
    }
    

    程序的输出结果是:
    Copy Constructor called
    1,2

    第 9 行,复制构造函数的参数加不加 const 对本程序來说都一样。但加上 const 是更好的做法,这样复制构造函数才能接受常量对象作为参数,即才能以常量对象作为参数去初始化别的对象。

    第 17 行,就是以 c1 为参数调用第 9 行的那个复制构造函数初始化的。该复制构造函数执行的结果是使 c2 和 c1 相等,此外还输出Copy Constructor called。

    可以想象,如果将第 10 行删去或改成real = 2*c.real; imag = imag + 1;,那么 c2 的值就不会等于 c1 了。也就是说,自己编写的复制构造函数并不一定要做复制的工作(如果只做复制工作,那么使用编译器自动生成的默认复制构造函数就行了)。但从习惯上来讲,复制构造函数还是应该完成类似于复制的工作为好,在此基础上还可以根据需要做些別的操作。

    构造函数不能以本类的对象作为唯一参数,以免和复制构造函数相混淆。例如,不能写如下构造函数:

    Complex (Complex c) {...}
    
    展开全文
  • 复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。一个类中写两个复制构造函数...

    一、浅拷贝和深拷贝

    对于普通类型的对象来说,它们之间的复制是很简单的,而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。

    在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,假设对象B中有一个成员变量指针已经申请了内存,此时执行:A=B。其实只是新建了一个代指对象A的指针,这个指针指向B的地址,这时,A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

    深拷贝(a)和浅拷贝(b)可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
    在这里插入图片描述
    深拷贝示例

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    class String {
    private:
        char * str;
    public:
        String() :str(NULL) { }
        String(String & s);
        const char * c_str() const { return str; };
        String & operator = (const char * s);
        String & operator = (const String & s);
        ~String();
    };
    String::String(String & s)
    {
        if (s.str) {
            str = new char[strlen(s.str) + 1]; // 添加\0空间
            strcpy(str, s.str);
        }
        else
            str = NULL;
    }
    String & String::operator = (const String & s)
    {
        if (str == s.str)
            return *this;
        if (str)
            delete[] str;
        if (s.str) {           //s. str不为NULL才执行复制操作
            str = new char[strlen(s.str) + 1];
            strcpy(str, s.str);
        }
        else
            str = NULL;
        return *this;
    }
    String & String::operator = (const char * s)   //重载"="以使得 obj = "hello"能够成立
    {
        if (str)
            delete[] str;
        if (s) {            //s不为NULL才会执行拷贝
            str = new char[strlen(s) + 1];
            strcpy(str, s);
        }
        else
            str = NULL;
        return *this;
    }
    String::~String()
    {
        if (str)
            delete[] str;
    };
    
    =======================
    String s1, s2;
    s1 = "this";
    s2 = "that";
    s2 = s1;
    

    二、复制构造函数

    复制构造函数是构造函数的一种,也称拷贝构造函数,它只有一个参数,参数类型是本类的引用

    复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。一个类中写两个复制构造函数,一个的参数是 const 引用,另一个的参数是非 const 引用,也是可以的。

    如果类的设计者不写复制构造函数,编译器就会自动生成复制构造函数。大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制,即使得目标对象的每个成员变量都变得和源对象相等。编译器自动生成的复制构造函数称为“默认复制构造函数”。

    注意,默认构造函数(即无参构造函数)不一定存在,但是复制构造函数总是会存在。

    默认复制构造函数

    #include<iostream >
    using namespace std;
    class Complex
    {
    public:
        double real, imag;
        Complex(double r, double i) {
            real= r; imag = i;
        }
    };
    int main(){
        Complex cl(1, 2);
        Complex c2 (cl);              //用复制构造函数初始化c2
        cout<<c2.real<<","<<c2.imag;  //输出 1,2
        return 0;
    }
    

    编译器自动生成的那个默认复制构造函数的参数才能和 c1 匹配。
    调用默认复制构造函数进行初始化的。初始化的结果是 c2 成为 c1 的复制品,即 c2 和 c1 每个成员变量的值都相等。

    自定义复制构造函数

    #include<iostream>
    using namespace std;
    class Complex{
    public:
        double real, imag;
        Complex(double r,double i){
            real = r; imag = i;
        }
        Complex(const Complex & c) // 最好加上const,这样复制构造函数才能接受常量对象作为参数,即才能以常量对象作为参数去初始化别的对象。
        {
            real = c.real; imag = c.imag;
            cout<<"Copy Constructor called"<<endl ;
        }
    };
    int main(){
        Complex cl(1, 2);
        Complex c2 (cl);  //调用复制构造函数
        cout<<c2.real<<","<<c2.imag;
        return 0;
    }
    

    拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。
    例如:类X的拷贝构造函数的形式为X(X& x)。

    三、复制构造函数被调用的三种情况

    复制构造函数在以下三种情况下会被调用。

    3.1 用一个对象去初始化同类的另一个对象

    当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用。
    例如,下面的两条语句都会引发复制构造函数的调用,用以初始化 c2。
    Complex c2(c1);
    Complex c2 = c1;
    这两条语句是等价的。

    注意,第二条语句是初始化语句,不是赋值语句。赋值语句的等号左边是一个早已有定义的变量,赋值语句不会引发复制构造函数的调用。例如:
    Complex c1, c2; c1 = c2 ;
    c1=c2;

    3.2 函数的参数是类的对象

    那么当 Func 被调用时,类 A 的复制构造函数将被调用。
    换句话说,作为形参的对象,是用复制构造函数初始化的,而且调用复制构造函数时的参数,就是调用函数时所给的实参。

    #include<iostream>
    using namespace std;
    class A{
    public:
        A(){};
        A(A & a){
            cout<<"Copy constructor called"<<endl;
        }
    };
    
    void Func(A a){ }
    
    int main(){
        A a;
        Func(a);
        return 0;
    }
    ==========输出结果=============
    Copy constructor called
    

    Func 函数的形参 a 在初始化时调用了复制构造函数。
    函数的形参的值等于函数调用时对应的实参,现在可以知道这不一定是正确的。如果形参是一个对象,那么形参的值是否等于实参,取决于该对象所属的类的复制构造函数是如何实现的。例如上面的例子,Func 函数的形参 a 的值在进入函数时是随机的,未必等于实参,因为复制构造函数没有做复制的工作。

    以对象作为函数的形参,在函数被调用时,生成的形参要用复制构造函数初始化,这会带来时间上的开销。如果用对象的引用而不是对象作为形参,就没有这个问题了。但是以引用作为形参有一定的风险,因为这种情况下如果形参的值发生改变,实参的值也会跟着改变。

    如果要确保实参的值不会改变,又希望避免复制构造函数带来的开销,解决办法就是将形参声明为对象的 const 引用。例如:
    void Function(const Complex & c)
    {

    }
    这样,Function 函数中出现任何有可能导致 c 的值被修改的语句,都会引发编译错误。

    3.3 函数的返冋值是类的对象

    函数的返冋值是类 A 的对象,则函数返冋时,类 A 的复制构造函数被调用。
    换言之,作为函数返回值的对象是用复制构造函数初始化的,而调用复制构造函数时的实参,就是 return 语句所返回的对象。例如下面的程序:

    #include<iostream>
    using namespace std;
    class A {
    public:
        int v;
        A(int n) { v = n; };
        A(const A & a) 
        {
            v = a.v;               // 复制构造函数在此完成了复制的工作
            cout << "Copy constructor called" << endl;
        }
    };
    A Func() {
        A a(4);
        return a;                   //返回值是一个对象,该对象就是用复制构造函数初始化的
    }
    int main() {
        cout << Func().v << endl;   //调用了 Func 函数
        return 0;
    }
    ===========输出结果:==============
    Copy constructor called
    4
    

    需要说明的是,有些编译器出于程序执行效率的考虑,编译的时候进行了优化,函数返回值对象就不用复制构造函数初始化了,这并不符合 C++ 的标准。上面的程序,用 Visual Studio 2010 编译后的输出结果如上所述,但是在 Dev C++ 4.9 中不会调用复制构造函数。把第 14 行的 a 变成全局变量,才会调用复制构造函数。

    展开全文
  • 复制构造函数是一种特殊的...复制构造函数的参数传递方式必须按引用来进行传递,请看实例:#include #include using namespace std ; class Student { private : char name[8]; int age ; char sex ;

    复制构造函数是一种特殊的构造函数,有一般构造函数的特性。它的功能是用一个已知的对象来初始化一个被创建的同类对象。复制构造函数的参数传递方式必须按引用来进行传递,请看实例:

    #include <iostream>
    #include <cstring>
    using namespace std ; 
    class Student 
    {
    	private :
    		char name[8];
    		int age ;
    		char sex ; 
    		int score ;
    	public :
    		void disp(); //打印信息的函数声明
    		Student(char name[],int age , char sex ,int score); //构造函数声明
    		Student(Student &dx);	//复制构造函数的声明
    		~Student(); //析构函数的声明
    };
    //打印信息函数的实现
    void Student::disp()
    {
    	cout << this->name << endl ; 
    	cout << this->age << endl ; 
    	cout << this->sex << endl ; 
    	cout << this->score << endl ;
    }
    //构造函数的实现 
    Student::Student(char name[],int age , char sex ,int score)
    {
    	strcpy(this->name,name);
    	this->age = age ; 
    	this->sex = sex ;
    	this->score = score ;
    }
    //复制构造函数的实现
    Student::Student(Student &dx)
    {
    	strcpy(this->name , dx.name);
    	this->age = dx.age ; 
    	this->sex = dx.sex ;
    	this->score = dx.score ;
    } 
    //析构函数的实现
    Student::~Student()
    {
    	cout << "程序结束" << endl ;
    } 
    
    int main(void)
    {
    	Student stu1("YYX",23,'N',86);
    	Student stu2(stu1); 
    	stu1.disp() ;
    	stu2.disp() ;
    	return 0 ;
    }
    运行结果:

    YYX

    23

    N

    86

    YYX

    23

    N

    86

    程序结束

    程序结束

    展开全文
  • 一般来讲出现这个错误时,是因为复制构造函数的参数没有加const,加上就好了
  • 如果构造对象有参数,则初始化时会调用对应参数的构造函数,否则就会调用无参数的构造函数,所以一般会写一个无参数的构造函数供别人修改程序使用。如果自己已经定义一个构造函数,则编辑器不会再自己生成默认...
  • C++类用三个特殊的成员函数:复制构造函数、赋值操作符和析构函数 来决定类对象之间的初始化或赋值时发生...于是复制构造函数的原型为: class BOOK { public: BOOK(const BOOK& rhs); //构造函数一 BOOK(string &
  • 复制构造函数的参数传递方式必须按引用来进行传递,请看实例: #include #include using namespace std ; class Student { private : char name[8]; int age ; char sex ; int score ; public : void disp...
  • 定义默认构造函数(default constructor)的一般形式为: 类名() { 函数体 } 它由不带参数的构造函数,或者所有形参均是默认参数的构造函数定义。与默认构造函数相对应对象定义形式为: 类名 对象名; 任何一个...
  • 是一种特殊的构造函数,在生成一个实例的时候,一般会同时生成一个默认的复制构造函数复制构造函数完成一些基于同一类的其他对象的构建及初始化工作。 拷贝构造函数的特点 该函数名与类名同名,因为它也是一种...
  • 文章目录默认构造函数和复制构造函数1 定义默认构造函数2 隐式类类型转换3 复制构造函数与合成复制构造函数3.1 复制构造函数3.2 合成复制构造函数4 深复制与浅复制 默认构造函数和复制构造函数 1 定义默认构造函数 ...
  • 什么是复制构造函数

    千次阅读 2016-03-14 13:58:06
    复制构造函数又称为拷贝构造函数,是一种特殊构造函数,它由编译器调用来完成一些基于同一类其他对象构建及初始化。它存在唯一一个参数是不可变。这个函数经常在函数调用期间于用户定义类型值传递及返回。...
  • 复制构造函数参数为类对象本身引用,用于根据一个已存在对象复制出一个新该类对象,一般在函数中会将已存在对象数据成员值复制一份到新创建对象中 复制构造函数是一种特殊构造函数,具有单个形参,...
  • c++复制构造函数

    2018-04-16 22:13:01
     拷贝构造函数一类特殊的构造函数,具有一般构造函数的所有特性,其形参是本类对象的引用,起作用是使一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个对象。初始化对象的每个数据成员都...
  • 浅析复制构造函数

    2013-06-05 18:01:08
    其作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。如果程序员没有没有定义类的复制构造函数,系统会在必要时自动生成一个隐含的复制构造函数。这个隐含的复制构造函数的功能...
  • 它的作用是使用一个已经存在的对象(此对象由复制构造函数的参数决定),去初始化同类的一个新对象。那么复制构造函数一般在什么情况下被调用呢,有三种情况: (1)当用类的一个对象去初始化该类的另一个对象的...
  • C++复制构造函数和赋值构造函数的代码实例 默认编译器都会自动加上一个,一般都是用常对象作为参数。 测试程序: class CComplex { private: double real; double imag; public: CComplex(double r,...
  • C++复制构造函数和拷贝构造函数

    千次阅读 2014-03-04 14:53:03
    1 拷贝构造函数参数的...对于一个类X,如果一个构造函数的第一个参数是下列之一: a) X& b) const X& c) volatile X& d) const volatile X& 因此 X::X(X&, int=1); //是拷贝构造函数 并且类中可以存在超过一个拷
  • 复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。一个类中写两个复制构造函数...
  • 一、复制构造函数的定义 复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性。复制构造函数创建一个新的对象,作为另一个对象的拷贝。复制构造函数只含有一个形参,而且其形参为本类对象的引用。复制...
  • 作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。 个人理解:构造函数是用于创建一个类的新的对象。而复制构造函数就是复制一个已经存在的对象。(构造函数创建一个新的人,...
  • C++ Copy Constructor (拷贝构造函数,复制构造函数)

    万次阅读 多人点赞 2014-03-14 08:12:53
    Copy Constructor 是一个特殊的构造函数,一般只有一个参数,这个参数一般是用const修饰,对自己类一个引用(reference)。什么时候会用到Copy Constructor? 当我们定义一个对象时,它是由另外一个对象来初始化...
  • 复制构造函数:用一个已经存在的对象构造一个不存在的对象。 赋值运算:用一个已经存在的...复制构造函数的特点: 1)该函数名与类同名,并且该函数不指定返回类型。 2)该函数只有一个参数,并且是对某个对象的引用
  • 1 复制构造函数复制构造函数是一个特殊的构造函数,只有单个...2 自定义复制构造函数自定义复制构造函数的一般形式:类名::类名(类名 & 对象名){ 复制构造函数的函数体}其中对象名是用来初始化另一个对象的应用。 #
  • 常见的构造函数有三种写法:无参构造函数一般构造函数复制构造函数C++的构造函数可以有多个,创建对象时编译器会根据传入的参数不同调用不同的构造函数。1、无参构造函数如果创建一个类,没有写任何构造函数,则系统...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 226
精华内容 90
关键字:

复制构造函数的参数一般是