精华内容
下载资源
问答
  • 2021-05-22 12:22:30

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

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

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

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

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

    #include

    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<

    return 0;

    }

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

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

    #include

    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<

    }

    };

    int main(){

    Complex cl(1, 2);

    Complex c2 (cl); //调用复制构造函数

    cout<

    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) {...}

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

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

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

    Complex c2(c1);

    Complex c2 = c1;

    这两条语句是等价的。

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

    Complex c1, c2; c1 = c2 ;

    c1=c2;

    这条语句不会引发复制构造函数的调用,因为 c1 早已生成,已经初始化过了。

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

    #include

    using namespace std;

    class A{

    public:

    A(){};

    A(A & a){

    cout<

    }

    };

    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 的值被修改的语句,都会引发编译错误。

    思考题:在上面的 Function 函数中,除了赋值语句,还有什么语句有可能改变 c 的值?例如,是否允许通过 c 调用 Complex 的成员函数?

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

    #include

    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;

    return 0;

    }

    程序的输出结果是:

    Copy constructor called

    4

    第19行调用了 Func 函数,其返回值是一个对象,该对象就是用复制构造函数初始化的, 而且调用复制构造函数时,实参就是第 16 行 return 语句所返回的 a。复制构造函数在第 9 行确实完成了复制的工作,所以第 19 行 Func 函数的返回值和第 14 行的 a 相等。

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

    更多相关内容
  • C++类用三个特殊的成员函数:复制构造函数、赋值操作符和析构函数 来决定类对象之间的初始化或赋值时发生什么。所谓的“复制控制”即通过这三个成员函数控制对象复制的过程。本篇文章将介绍复制构造函数。  复制...
  • 构造函数 是为了让我们自己去规定 , 我们定义对象的初始化。 #include <iostream> using std::cin; using std::cout; using std::endl; class Clock{ public: void setTime(int newS = 0, int newM = 0, ...

    一、构造函数

    是为了让我们自己去规定 , 我们定义对象的初始化。
    这里给出一段程序,作用是按格式输出 输入的时间。

    #include <iostream>
    using std::cin;
    using std::cout;
    using std::endl;
    class Clock{ 
        public:
        	void setTime(int newS = 0, int newM = 0, int newH = 0){
        	//这一步如果想要输出默认值,应该把主函数里的setTime函数中的参数删除。
                second = newS;
                minute = newM;
                hour = newH; 
            }
        	void showTime();
        private:
            int second, minute, hour;
    };
    void Clock::showTime(){
       cout << hour << ":" << minute << ":" << second <<endl;
    }
    int main(){
        Clock MyClock;
        int second, minute, hour;
        cin >> second >> minute >> hour;
        MyClock.setTime(second, minute, hour);
        MyClock.showTime();
        return 0;
    }
    

    构造函数的性质:
    ● 不能定义返回值类型,也不能写return语句
    ●可以有形参,也可以没有形参,可以带有默认参数
    ●函数名必须和类名完全相同
    ●可以重载

    当我们没有写构造函数时,系统会为我们自动生成一个默认构造函数,这个默认构造函数的参数列表和内容都是空的,所以他什么都不会做!

    现在 我们需要创建一个默认构造函数,让对象早初始化的时候把所有的时间全部设置为0。

    //在类内定义构造函数时,不能有返回值类型,且构造函数的名字要和类一样,可以有形参也可以没有形参,这里的第一种定义是没有形参的类型:
    class Clock{
    public:
        Clock(){
            second = 0;
            minute = 0;
            hour = 0;
        }
    //如果不写构造函数,那么系统自动生成的构造函数 就是
        Clock(){}
    //函数里没有任何内容,所以也不会有操作
    

    第二种定义类型是有参数的形式:

    Class Clock{
    public:
    	Clock(int newS, int newM, int newH){
        second = newS;
        minute = newM;
        hour = newH;
    }
    }
    
    //或者在类外实现构造函数
    Class Clock{
    public:
    	Clock(int newS, int newM, int newH);
    	}
    Clock::Clock(int newS, int newM, int newH){
        second = newS;
        minute = newM;
        hour = newH;
    }
    这里在类外实现构造函数时,函数名前面仍然不要写函数的返回值类型 ,
    实现类外构造函数 : 在类内对函数定义,然后在类外 用 
     类名 :: 函数名 ( 参数 ) { 函数体 }   的形式在类外实现构造函数。 
    
    而在类外实现普通函数时,也是在类内先对函数进行定义,然后在类外 用
    返回值类型 类名 :: 函数名 ( 参数 ) { 函数体 } 实现,这里需要在类
    名前面加上返回值类型
    

    调用带参数的构造函数时,是在对象创建时被调用的:

     Clock MyClock2(1,2,3);
    

    二、复制构造函数

    用一个已有的对象,来执行一个新的对象的构造
    ●复制构造函数具有一般构造函数的所有特性,它的形参是本类的一个对象的引用,作用是用一个已经存在的对象(函数的参数)来初始化一个新的对象。
    ●复制构造函数的的使用方式 就是引用传参

    引用就是 给一个已经存在的变量起一个别名,所以用它的变量名或者别名都可以操作该变量, 复制构造函数就是给已经存在的构造函数起一个别名。

    因为:值传递就是当函数发生调用的时候,给形参分配内存空间,然后用实参的值来初始化形参,但是如果参数是一个对象,值传递“初始化形参”这个过程就会造成很多额外的时间开销,浪费系统资源,如果使用引用就不会有这样的问题。

    复制构造函数能实现同类对象之间数据成员的传递。 当我们没有定义类的构造韩函数时,系统就会在必要的时候自动生成一个隐含的复制构造函数,他的作用是把初始对象的每一个数据成员的值都复制到新建的对象中,这就完成了同类对象的复制。
    复制构造函数的具体声明方式 :

    class 类名{
    public:
    	类名(类名& 对象名){
    	//实现
    	}
    };
    

    实例:
    先有一个point类,表示屏幕上的一个点——它包括两个 int 类的私有成员 x , y, 表示这个点的坐标。

    class Point {
    public:
    	Point(Point &p);
    private:
    	int x,y;
    };
    
    //以下代码可实现复制构造函数
    Point::Point(Point &p){
    	x = p.x;
    	y = p.y;
    }
    //这里复制构造函数访问了Point类的实例对象p的两个私有成员变量 x,y 。我们需要注意的是 ———— private 与 public 的区别是对类来说的,而不是对对象来说。 拷贝构造函数是Point类的成员函数————所以它可以访问类的私有成员变量,这跟具体的对象无关。
    

    复制构造函数被调用主要的三种情况:
    ●当用类的一个对象去初始化该类的另一个对象的时候:

    Point a(1,2);
    Point b(a);//用对象a初始化对象b,复制构造函数被调用
    Point c = b;//用对象b给对象c赋值,复制构造函数被调用
    

    ●当函数的形参是类的对象,调用函数是进行形式结合的时候:

    void f(Point p){
        //函数体
    }
    int main(){
        Point a(1,2);
        f(a);
        return 0;
    }
    

    ●当函数返回值是类的对象,函数执行完成返回调用者的时候:

    Point g(){
        Point a(1,2);
        return a;
    }
    /*定义在函数中的变量都是局部变量,当函数返回值的时候这些局部变量
    都被销毁了。同样,在函数中创建的对象也相同。 return a 这一步返
    回的并不是 a 这个对象本身,而是通过复制构造函数,在主调函数中用a
    重新构造的对象。在函数调用返回的时候,原来的临时对象 a 的使命已
    经完成,随着整个函数中的其他临时变量一起被销毁了。*/
    

    对于复制构造函数,我们还可以自己实现一些有选择、有变化的复制:

    Point (point &p){
        x = p.x+10;
        p=p.y;
    }
    

    这个函数就会把每一个由复制构造得到的Point对象,横坐标+10.

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

    2021-01-19 23:44:42
    拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于: 通过使用另一个同类型的对象来初始化新创建的对象。 复制对象把它作为参数传递给...
  • C++——构造函数、析构函数以及复制构造函数

    千次阅读 多人点赞 2021-03-09 16:28:49
    文章目录一、构造函数1.1 构造函数是什么?1.2 为什么要有构造函数?1.3 如何使用构造函数?1.4 构造函数的实现二、使用步骤 一、构造函数 在程序执行的过程中,当遇到与对声明语句时,程序会向操作系统申请一定的...

    一、构造函数

    在程序执行的过程中,当遇到与对声明语句时,程序会向操作系统申请一定的内存空间用于存放新建的对象。但是与普通变量相比,类的对象特别复杂,编译器不知如何产生代码去初始化对象,这便引出了构造函数。

    1.1 构造函数是什么?

    C++中,构造函数是一种特殊的成员函数,在每次创建一个类的时候编译器都会默认调用构造函数进行初始化。

    1.2 为什么要有构造函数?

    构造函数的作用就是在对象被创建的时候,利用特定的值构造对象,将对象初始化为一个特定的状态。

    1.3 如何使用构造函数?

    要学会如何使用构造函数,首先需要了解构造函数的一些特殊性质:构造函数的函数名与类名相同,而且没有返回值;构造函数通常被声明为公有函数。

    Notes:只要类中有了构造函数,编译器就会在创建新对象的地方自动插入对构造函数调用的代码。所以构造函数在对象被创建的时候将会被自动调用。

    下面分别介绍常见的几种构造函数:

    1. 默认构造函数:
    class Clock
    {
    public:
        Clock()   //编译器自动生成的隐含的默认构造函数;
        {
            
        }
        ....
    };
    

    默认构造函数调用时无须提供参数。如果类中没有写构造函数,那么编译器会自动生成一个隐含的默认构造参数,该构造函数的参数列表和函数体都为空,这个构造函数不做任何事情。

    Notes: 无参数的构造函数与全缺省的构造函数都称为默认构造函数。

    Q:既然默认构造函数不做任何事情,那么为什么还要生成这个构造函数?

    答:因为在建立对象时自动调用构造函数时C++必然要做的事情。上述例子中,默认构造函数什么都没有做,但是有些函数体为空的构造函数并非什么都不做,因为它还要负责基类的构造和成员对象的构造。

    1. 有参数的构造函数和无参数的构造函数
    class Clock
    {
    public:
        Clock(int NewH,int NewM,int NewS);  //有参数的构造函数
        Clock()   //无参数的构造函数
        {
            hour = 0;
            minute = 0;
            second = 0;
        }
        void SetTime(int NewH,int NewM,int NewS);
        void ShowTime();
    
    private:
        int hour,minute,second;
    };
    
    int main()
    {
        Clock(0,0,0); //调用有参数的构造函数
        Clock my_clock;  //调用无参数的构造函数
        return 0;
    }
    
    

    上述例子中出现了两种重载的构造函数的形式:有参数的和无参数的(即默认构造函数)

    1.4 构造函数的实现

    
    Clock::Clock(int NewH, int NewM, int NewS) 
    {
        hour = NewH;
        minute = NewM;
        second = NewS;
    }
    

    二、复制构造函数

    生成一个对象的副本有两种途径,第一种途径是建立一个新的对象,然后将原始对象的数据成员取出来,赋值给新对象。这样做显然太繁琐了,所以为了使得一个类具有自行复制本类对象的能力,复制构造函数被引出。

    2.1 什么是复制构造函数?

    复制构造函数是一种特殊的构造函数,其具有一般构造函数的所有特性,其形参是本类对象的引用。

    2.2 为什么要有复制构造函数?

    复制构造函数的作用是使得一个已经存在的对象(由复制构造函数的参数指定),去初始化一个同类的一个新对象。如果程序没有定义类的复制构造函数,系统就会在必要时自动生成一个隐藏的复制构造函数。这个隐藏的复制构造函数的功能是,把初始值对象的每个数据成员复制到新建立的对象中去。这样得到的对象和原本的对象具有相同的数据成员和属性。

    2.3 复制构造函数的功能

    在说明复制构造函数的功能之前,我们先看一下声明和实现复制构造函数的一般方法:

    class 类名
    {
    public:
        类名(形参); //构造函数
        类名(类名& 对象名); //复制构造函数
        ...
    };
    
    类名::类名(类名 &对象名) //复制构造函数的实现
    {
        //函数体
    }
    

    前面我们知道,普通的构造函数在对象被创建的时候调用,而复制构造函数在下面3种情况下均会被调用:

    例:

    class Point
    {
    public:
        Point(int x = 0,int y = 0)
        {
            _x = x;
            _y = y;
        }
        Point(Point& p); //复制构造函数
        int GetX()
        {
            return _x;
        }
        int GetY()
        {
            return _y;
        }
    
    private:
        int _x,_y;
    };
    
    1. 当用类的一个对象去初始化另一个对象时:
    int main()
    {
        Point a(1,2);
        Point b(a); //用对象a初始化对象b时,复制构造函数被调用
        Point c = a; //用对象a初始化对象c时,复制构造函数被调用
        return 0;
    }
    

    Notes:上面对b和c的初始化都能够调用复制构造函数,两种写法是等价的,执行的操作完全相同。

    1. 如果函数的形参是类的对象,调用函数时,进行形参和实参结合时:
    void Fun(Point p)
    {
        //函数体
    }
    
    int main()
    {
        Point a(1,2);
        Fun(a); //函数的形参为类的对象,当调用对象时,复制构造函数被调用.
        return  0;
    }
    

    Notes:只有把对象用值传递的时候,才会调用复制构造函数。如果传递的是引用,则不会调用复制构造函数。所以这也是传递引用会比传值的效率高的原因。

    1. 如果函数的返回值是类的对象,函数执行完成返回调用者时:
    Point Fun()
    {
        Point a(1,2);
        return a;  //函数Fun的返回值是类的对象,返回函数值的时候,调用复制构造函数
    }
    
    int main()
    {
        Point b;
        b = Fun();
        return 0;
    }
    

    Q:为什么在这种情况下,返回函数值的时候会调用复制构造函数?

    答:函数Fun()将a返回给了主函数,但是我们都知道a是Fun()的局部变量,当Fun()函数的生命周期结束的时候,a也就消亡了,不可能在返回主函数后继续生存。所以在这种情况下编译器会在主函数中创建一个无名的临时对象,该临时对象的生命周期仅仅在b = Fun()中。当执行语句return a时,实际上是调用复制构造函数将a的值复制到无名临时对象中。当函数Fun()运行结束时,对象a消失,但是临时对象会存在于b = Fun()中。当计算这个表达式后,临时对象也就完成了它的工作。

    三、析构函数

    我们刚讨论了当一个局部变量随着它的函数生命周期结束的时候,函数中的对象也会消失,那么在对象,要消失的时候(比如构造对象的时候,在函数中用malloc动态申请了空间)谁来做这些所谓的“善后”工作呢?这样我们就引出了析构函数。

    什么是析构函数?

    与构造函数一样,析构函数通常也是类的一个公有成员函数,它的名称是由类名前面加一个"~"构成,没有返回值。析构函数与构造函数不同的是,析构函数不接受任何参数!(参数可以是虚函数),如果我们不自行定义析构函数,则编译器同样会自动生成一个隐藏的析构函数,它的函数体为空。

    下面我们看一下析构函数的声明:

    class Clock
    {
    public:
        Clock(int NewH,int NewM,int NewS);  //有参数的构造函数
        Clock()   //无参数的构造函数
        {
            hour = 0;
            minute = 0;
            second = 0;
        }
        void SetTime(int NewH,int NewM,int NewS);
        void ShowTime();
        ~Clock(); //析构函数
    
    private:
        int hour,minute,second;
    };
    

    Notes:函数体为空的析构函数并不是什么都不做。

    Tips:
    类的构造顺序是按照语句的顺序进行构造
    类的析构函数调用完全按照构造函数调用的相反顺序进行调用
    1.全局对象先于局部对象进行构造
    2.静态对象先于普通对象进行构造

    展开全文
  • 复制构造函数是一种特殊的构造函数,有一般构造函数的特性。它的功能是用一个已知的对象来初始化一个被创建的同类对象。复制构造函数参数传递方式必须按引用来进行传递,请看实例: #include #include using ...
  • (其实很多名字,只要静下心来想一想,就真的是顾名思义呀)拷贝又称复制,因此拷贝构造函数又称复制构造函数。百度百科上是这样说的:拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的...
  • c++复制构造函数详解

    千次阅读 2020-07-12 16:32:41
    复制构造函数(Copy constructor)是c++中的一个特殊构造函数,也称拷贝构造函数,它只有一个参数参数类型为同类对象的引用。 如果没有定义复制构造函数,那么编译器将生成默认的复制构造函数。默认的复制构造函数...

    基本概念

    复制构造函数(Copy constructor)是c++中的一个特殊构造函数,也称拷贝构造函数,它只有一个参数,参数类型为同类对象的引用。

    如果没有定义复制构造函数,那么编译器将生成默认的复制构造函数。默认的复制构造函数完成复制的功能。

    复制构造函数的参数为同类对象的引用,可以是常应用,也可以是非常引用。形如类名::类名(类名&)类名::类名(const 类名&)

    默认复制构造函数

    class Complex {//复数类
    public:
    	double real, imag;//分别表示实部以及虚部
    public:
    	//构造函数
    	Complex(double r,double i) {
    		real = r;
    		imag = i;
    	}
    };
    

    对于上面的复数类,假设我们有如下的初始化:

    int main() {
    	Complex c1(5, 2);
    	cout << "c1.real=" << c1.real << "\tc1.imag=" << c1.imag << endl;
    	Complex c2(c1);//调用复制构造函数初始化c2
    	cout << "c2.real=" << c2.real << "\tc2.imag=" << c2.imag << endl;
    	return 0;
    }
    

    在上面的初始化工作中,我们调用构造函数对c1进行初始化工作,然后输出c1的实部以及虚部。然后用c1去初始化c2,此时将调用编译器自动生成的构造函数将c2初始化为和c1一样,然后输出c2的实部以及虚部。运行上面的程序,得到如下的输出:

    c1.real=5       c1.imag=2
    c2.real=5       c2.imag=2
    

    可以看到此时c2被初始化为和c1相同。

    编写复制构造函数

    在上面的例子中,我们并没有编写复制构造函数,此时编译器将生成一个默认的复制构造函数完成复制工作。

    当我们自己编写了复制构造函数之后,编译器将不再生成默认的复制构造函数。如下面的例子所示:

    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 << "调用复制构造函数!!" << endl;
    	}
    };
    

    对于上面的类,在复制构造函数被调用的时候将完成复制的工作,并且向控制台输出调用复制构造函数!!,假设我们有如下的初始化:

    int main() {
    	Complex c1(5, 2);
    	cout << "c1.real=" << c1.real << "\tc1.imag=" << c1.imag << endl;
    	Complex c2(c1);//调用复制构造函数初始化c2
    	cout << "c2.real=" << c2.real << "\tc2.imag=" << c2.imag << endl;
    	return 0;
    }
    

    执行后可以得到如下的结果:

    c1.real=5       c1.imag=2
    调用复制构造函数!!
    c2.real=5       c2.imag=2
    

    可以看到,此时我们自己编写的复制构造函数被调用,并且向屏幕输出了调用复制构造函数!!

    错误用法

    复制构造函数的参数一定要是对同类对象的引用,不能为其它的。

    class Complex {
    public:
    	double real, imag;
    	Complex(double r,double i) {
    		real = r;
    		imag = i;
    	}
    	Complex(Complex c) {//错误的写法
    		real = c.real;
    		imag = c.imag;
    		cout << "调用复制构造函数!!" << endl;
    	}
    };
    

    如上所示,我们错误的将参数Complex& c写为了Complex c,此时我们的编译将无法通过,在visual studio 2019中将得到以下的报错:

    error C2652: “Complex”: 非法的复制构造函数: 第一个参数不应是“Complex”
    message : 参见“Complex”的声明
    error C2333: “Complex::Complex”: 函数声明中有错误;跳过函数体
    error C2558: class“Complex”: 没有可用的复制构造函数或复制构造函数声明为“explicit”
    

    总之,复制构造函数的参数一定要是同类对象的引用

    复制构造函数起作用的情况

    用一个对象来初始化正在构造的对象变量

    如上面编写复制构造函数小节中所展示的那样,当我们用同类的一个对象去初始化另一个对象时,会导致构造函数被调用。

    需要注意的是:

    Complex c1(5, 2);
    Complex c2(c1);
    Complex c3 = c1;//初始化语句,非赋值语句
    

    上面的第三天语句为初始化语句,并非赋值语句。

    函数参数作为对象传值

    如果某函数有一个参数是类的对象,那么该函数被调用时,该类的复制构造函数将被调用。

    class Complex {//复数类
    public:
    	Complex() {};
    	Complex(const Complex& c) {//复制构造函数
    		cout << "调用复制构造函数!!" << endl;
    	}
    };
    

    对于上面的类,假设我们有如下调用:

    void fun(Complex c){}
    int main() {
    	Complex c;
    	fun(c);//调用fun(Complex c)
    	return 0;
    }
    

    其中我们定义了一个函数fun(Complex c),其参数为一个Complex对象,当我们在调用fun(Complex c)的时候,形参c将被初始化,此时将调用复制构造函数完成初始化工作,产生如下的输出:

    调用复制构造函数!!
    

    需要注意的是,如果函数的参数为对象的引用或常引用时,将不会导致构造函数被调用,如下所示:

    void fun(Complex &c){}
    

    函数返回一个对象

    如果函数的返回值是某类的对象,则函数返回时,复制构造函数将被调用。

    class Complex {//复数类
    public:
    	Complex() {};
    	Complex(const Complex& c) {//复制构造函数
    		cout << "调用复制构造函数!!" << endl;
    	}
    };
    

    对于上面的类有如下调用:

    Complex fun(){
    	Complex c(2,3);
    	return c;
    }
    int main() {
    	cout << fun().real << endl;
    	return 0;
    }
    

    函数fun()返回一个Complex类的对象,在调用fun()函数时会导致复制构造函数被调用。

    注意事项

    • 上述情形未必会调用复制构造函数。因为C++标准允许编译器实现做一些优化。例如:Class X b=X();

    优化

    当对象作为函数参数,在对函数进行调用时会调用复制构造函数对形参进行初始化工作,此时会产生额外的开销,我们可以将函数的参数写为对象的引用来避免额外的开销,如果担心对象的值在函数中会被改变,我们也可以用常引用的方式。

    对于如下的写法:

    Complex fun(Complex c){}
    

    我们可以改写为:

    Complex fun(Complex& c){}
    Complex fun(const Complex& c) {}
    
    展开全文
  • 拷贝和复制是一个意思,对应的英文单词都是copy。对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的...
  • 2、函数fun( )的形参是对象时,传递参数时,复制构造函数会被调用 3、函数的返回值是对象时,返回结果时,复制构造函数会被调用 接下来依次看一下这三种情况。 首先是类的定义 class node { public: int x, y; ...
  • 如果类成员都是简单类型(如标量值),则编译器生成的复制构造函数已足够,无需定义自己的类型。 如果类需要更复杂的初始化,则需要实现自定义复制构造函数。例如,如果类成员是指针,则需要定义复制构造函数以分配...
  • 文章目录默认构造函数和复制构造函数1 定义默认构造函数2 隐式类类型转换3 复制构造函数与合成复制构造函数3.1 复制构造函数3.2 合成复制构造函数4 深复制与浅复制 默认构造函数和复制构造函数 1 定义默认构造函数 ...
  • C++类和对象练习 构造函数 复制构造函数 缺省参数列表
  • 如果我们的拷贝构造函数参数不是引用,那么拷贝构造函数又会重复调用拷贝构造函数,就这样永远的递归调用下去了。   所以, 拷贝构造函数是必须要带引用类型的参数的, 而且这也是编译器强制性要求的。 为...
  • 拷贝构造函数(复制构造函数

    千次阅读 2019-03-17 15:44:34
    赋值构造函数 用一个对象初始化另一个对象 特别注意:初始化操作和 等号操作是两个不同的概念 1、初始化法 Class A { public: A(int a) { m_a = a; } A(int a,int b) { m_a = a; m_b = b; } A(const A...
  • C++中类的构造函数与复制构造函数

    千次阅读 2017-04-27 10:52:42
    在网络上有朋友提到“主要原因在于编译器的优化,当复制构造函数是public时,编译器就会根据这个特性来对代码进行优化。当程序运行时,编译器发现复制构造函数是public,则说明程序允许对象之间的复制,此时就会通过...
  • C++ 类对像构造时,需要对类成员变量完成初始化赋值操作。使用初始化列表完成这步操作在性能上有益处。什么好处呢?摆道理显得不够彻底。看书不如做实验。...  这里需要陈述一下“复制构造函数”和
  • 复制构造函数介绍浅拷贝深拷贝 介绍 复制构造函数用于将一个对象复制到新对象中。它用于初始化过程中(包括按值传递函数),而不是常规的赋值过程中,类型如下: Class_name(const Class_name &); 它接受一个...
  • 复制构造函数

    千次阅读 多人点赞 2018-09-03 11:11:35
    复制构造函数是一种特殊构造函数,在生成一个实例时,一般会同时生成一个默认的复制构造函数复制构造函数完成一些基于同一类的其他对象的构建及初始化工作。 特点 复制构造函数名与类名同名,因为它是一种...
  • C++ 构造函数,默认构造函数,析构函数,复制构造函数
  • 复制构造函数只有一个参数,并且是对同类对象的引用-------复制构造函数无法重载。 eg: Time time1(15, 10, 5);  Time time2(time1); //实参是对象名 2.两者被调用的情况不同:  对于赋值构造函数,只会在以下三...
  • 复制构造函数重载

    千次阅读 2019-12-21 13:33:35
    以下代码编译时要加:-fno-elide-constructors 来关闭编译器优化,否则可能看不到复制构造函数的调用。 #include <iostream> using std::cout; using std::endl; class A { public: A() = default; A(A&...
  • 它的作用是使用一个已经存在的对象(此对象由复制构造函数参数决定),去初始化同类的一个新对象。那么复制构造函数一般在什么情况下被调用呢,有三种情况: (1)当用类的一个对象去初始化该类的另一个对象的...
  • C++——复制构造函数的形参为什么要是const引用

    千次阅读 多人点赞 2017-04-24 14:17:41
    //复制构造函数一开始想到的原型 CBox cigar; CBox myBox(cigar); //如果编写这样一条语句 //那么将生成这样一条对复制构造函数的调用CBox::CBox(cigar);因为实参是通过按值传递机制传递的。在可以传递对象cigar之前...
  • 般来讲出现这个错误时,是因为复制构造函数参数没有加const,加上就好了
  • 什么是复制构造函数复制构造函数是一个成员函数,它使用同一个类的另一个对象初始化一个对象。函数原型如下: ClassName(const ClassName &old_obj); 下面是一个复制构造函数的简单示例: #include <...
  • 自动调用复制构造函数的情况有以下3种: 1)当用一个对象去初始化本类的另一个对象时,会调用复制构造函数。例如,使用下列形式的说明语句时,即会调用复制析构函数。 类名 对象名2(对象名1); 类名 对象名2 = 对象...
  • 复制构造函数 只有一个参数,即对同类对象的引用 形如 X::X(X& )或X::X(const X& ),二者选一,后者能以常量对象作为参数 如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造...
  • 然而,在实现拷贝构造函数和赋值符函数时,在函数里利用对象直接访问了私有成员变量,因而,产生了困惑.下面以具体实例进行说明: 疑惑:为什么第26行和第32行代码可以编译通过,而第39行和第40行代码会产生编译...
  • 拷贝构造函数(复制构造函数) 一、拷贝构造函数概念 拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于: 通过使用另一个同类型的对象...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 253,721
精华内容 101,488
关键字:

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