精华内容
下载资源
问答
  • 复制构造函数是构造函数的一种,也称拷贝构造函数,它只有一个参数,参数类型是本类的引用。复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的...

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

    复制构造函数的参数可以是 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 变成全局变量,才会调用复制构造函数。对这一点,读者不必深究。

    展开全文
  • 复制构造函数3.何时调用复制构造函数1.新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用2. 每当程序生成了对象副本时,编译器都将使用复制构造函数。4. copy_constructor.cpp演示初始化对象调用复制...

    1.特殊成员函数

    C++里面一些类的成员函数是自动定义的,具体地说,C++自动提供了下面这些成员函数:

    • 默认构造函数,如果没有定义构造函数;
    • 默认析构函数,如果没有定义;
    • 复制构造函数,如果没有定义
    • 赋值运算符,如果没有定义
    • 地址运算符,如果没有定义

    更准确地说,编译器将生成上述最后三个函数的定义, 如果你涉及到了上面的操作,而没有显式提供这些函数的话。

    例如, 如果您将一个对象赋给另一个对象,编译器将提供赋值运算符的定义。下面用代码的形式来描述:
    Demo 是本文当中演示使用到的类,有下面语句

    Demo d;
    Demo d1;
    d = d1; // 会被编译器翻译成 d.operator=(d1);
    

    因为 = 赋值运算符只能当作成员函数来进行重载
    运算符重载只能是成员函数
    所以class_name_c1 = class_name_c2; 这样的语句,class_name_c1会是那个调用的对象,而 class_name_c2 会是传递的形参,即 class_name_c1.operator=(class_name_c2);

    2.复制构造函数

    复制构造函数用于将一个对象复制到新创建的对象中
    也就是说,它用于初始化过程中(包括按值传递参数),而不是常规的赋值过程中。类的复制构造函数原型通常如下:

    Class_name(const Class_name &);
    

    它接受一个指向类对象的常量引用作为参数。例如, Demo类的复制构造函数的原型如下

    Demo(const Demo &);
    

    对于复制构造函数,需要知道两点:何时调用和有何功能。

    3.何时调用复制构造函数

    1.新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用

    这在很多情况下都可能发生,最常见的情况是将新对象显式地初始化为现有的对象。
    例如,假设m1是一个 Demo对象,则下面4种声明都将调用复制构造函数:

    Demo d1(m1); // # 1 calls Demo(const Demo &)
    Demo d1 = m1; //#2 calls Demo(const Demo &)
    Demo d1 = Demo(m1);// #3 calls Demo(const Demo &)
    Demo *pDemo =new Demo(m1);//#4  calls Demo(const Demo &)
    

    其中中间的2种声明可能会使用复制构造函数直接创建metoo和also,也可能使用复制构造函数生成一个临时对象,然后将临时对象的内容赋给 metoo和also,这取决于具体的实现。
    最后一种声明使用 motto初始化一个匿名对象,并将新对象的地址赋给 pDemo指针。

    上面的4条语句,可以参考本文的 copy_constructor.cpp 实际的例子演示!

    copy_constructor.cpp演示初始化对象调用复制构造函数的情景?

    2. 每当程序生成了对象副本时,编译器都将使用复制构造函数。

    具体地说,当函数按值传递对象函数返回对象时,都将使用复制构造函数。
    即下面两种情况
    第一种情况

    Demo d1(1, "d1");
    void func(Demo d_var)
    {
    	cout << "func(Demo d_var)" << endl;
    }
    
    func(d1); //这会导致复制构造函数被调用。用来创建 d_var
    

    第二种情况
    func执行完毕 d1就被释放了,return 的时候肯定会调用复制构造函数,将其保存下来。

    Demo func()
    {
    	Demo d1(1, "d1");
    	cout << "func()" << endl;
    	return d1;
    }
    

    后面也有详细的代码演示。
    记住,按值传递意味着创建原始变量的个副本,编译器生成临时对象时,也将使用复制构造函数。

    4. copy_constructor.cpp演示初始化对象调用复制构造函数的情景?

    1.第一种 Demo d1(m1);

    我们先来看Demo类的定义
    他有两个成员变量,一个是iAge代表年龄,一个是var_name 他代表的是类对象实例的名字, 例如在使用构造函数的时候就把这个变量名字传递进去 Demo demo(1, "demo"); 这样做的目的是为了,打印的时候区分每个地址对应的是哪一个对象。

    class Demo {
    private:
    	int iAge;
    	string var_name;
    public:
    	Demo() {
    		iAge = 0;
    		var_name = "temp";
    		cout << "Demo(), this(" << this->var_name << "):" << this << ", this->iAge:" << this->iAge << endl;
    	}
    	Demo(int i, string  name = "meng-yue") {
    		this->iAge = i;
    		this->var_name = name;
    		cout << "Demo(int i),this(" << this->var_name << "):" << this << ", i:" << i << ", this->iAge:" << this->iAge << endl;
    	}
    	Demo(const Demo & d_copy) {
    		cout << "Demo(const Demo &d),this(" << this->var_name << "):" << this << ", &d_copy(" << d_copy.var_name <<  "):" << &d_copy << endl;
    	}
    	~Demo() {
    		cout << "~Demo,this(" << this->var_name << "):" << this << endl;
    	}
    	void Show() {
    
    	}
    };
    

    main函数

    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo m1(1, "m1");
    	Demo d1(m1);
    	cout << "&d1:" << &d1 << endl;
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    
    

    copy_constructor.cpp

      /*
    	 author:梦悦foundation
    	 公众号:梦悦foundation
    	 可以在公众号获得源码和详细的图文笔记
     */
     
    #include <iostream>
    #include <typeinfo>
    #include <string>
     
    using namespace std;
    class Demo {
    private:
    	int iAge;
    	string var_name;
    public:
    	Demo() {
    		iAge = 0;
    		var_name = "temp";
    		cout << "Demo(), this(" << this->var_name << "):" << this << ", this->iAge:" << this->iAge << endl;
    	}
    	Demo(int i, string  name = "meng-yue") {
    		this->iAge = i;
    		this->var_name = name;
    		cout << "Demo(int i),this(" << this->var_name << "):" << this << ", i:" << i << ", this->iAge:" << this->iAge << endl;
    	}
    	Demo(const Demo & d_copy) {
    		cout << "Demo(const Demo &d),this(" << this->var_name << "):" << this << ", &d_copy(" << d_copy.var_name <<  "):" << &d_copy << endl;
    	}
    	~Demo() {
    		cout << "~Demo,this(" << this->var_name << "):" << this << endl;
    	}
    	void Show() {
    
    	}
    };
    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo m1(1, "m1");
    	Demo d1(m1);
    	cout << "&d1:" << &d1 << endl;
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    

    编译运行的结果:
    首先 执行Demo m1(1, "m1"); 然后能够看出来 m1 的地址是 0xbfb06380
    然后执行 Demo d1(m1); 这会导致复制构造函数的调用,去构造这一个新的类实例 d1;,然后能看到这个d1 的地址是 0xbfb06378, 同时它的name 是没有值,
    Demo(const Demo &d),this():0xbfb06378, &d_copy(m1):0xbfb06380

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(m1):0xbfb06380, i:1, this->iAge:1
    Demo(const Demo &d),this():0xbfb06378, &d_copy(m1):0xbfb06380
    &d1:0xbfb06378
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this():0xbfb06378
    ~Demo,this(m1):0xbfb06380
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    上面 d1 成员变量没有值的原因是因为我们的复制构造函数什么都没有干的原因。假如说我们不提供自己定义的复制构造函数,c++为类默认生成的复制构造函会采取逐个成员赋值的操作!即

    d1.iAge = m1.iAge;
    d1.var_name = m1.var_name;
    

    我们可以把自己写的那个默认构造函数注释掉,并且新增一个Show(),打印成员变量,看看运行的结果:
    在这里插入图片描述

    默认的赋值构造函数有什么问题?

    default_copy_constructor.cpp

      /*
    	 author:梦悦foundation
    	 公众号:梦悦foundation
    	 可以在公众号获得源码和详细的图文笔记
     */
     
    #include <iostream>
    #include <typeinfo>
    #include <string>
     
    using namespace std;
    class Demo {
    private:
    	int iAge;
    	string var_name;
    public:
    	Demo() {
    		iAge = 0;
    		var_name = "temp";
    		cout << "Demo(), this(" << this->var_name << "):" << this << ", this->iAge:" << this->iAge << endl;
    	}
    	Demo(int i, string  name = "meng-yue") {
    		this->iAge = i;
    		this->var_name = name;
    		cout << "Demo(int i),this(" << this->var_name << "):" << this << ", i:" << i << ", this->iAge:" << this->iAge << endl;
    	}
    #if 0	
    	Demo(const Demo & d_copy) {
    		cout << "Demo(const Demo &d),this(" << this->var_name << "):" << this << ", &d_copy(" << d_copy.var_name <<  "):" << &d_copy << endl;
    	}
    #endif	
    	~Demo() {
    		cout << "~Demo,this(" << this->var_name << "):" << this << endl;
    	}
    	void Show() {
    		cout << "Show(),this(" << this->var_name << "):" << this << ", this->iAge:" << this->iAge << endl;;
    	}
    };
    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo m1(1, "m1");
    	Demo d1(m1);
    	cout << "&d1:" << &d1 << endl;
    	d1.Show();
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    

    编译运行的结果:
    可以看出来 ,之前的分析默认的复制构造函数确实是按照逐成员复制的。
    在这里插入图片描述
    注意: 所以默认复制构造函数有一个隐患就是 因为是按值赋值,所以var_name 实际上指向的是同一块内存区域。所以需要定义自己的复制构造函数,防止析构的时候重复析构同一块内存区域!
    在这里插入图片描述

    2. 第二种 Demo d1 = m1;

    copy_constructor1.cpp

    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo m1(1, "m1");
    	Demo d1 = m1;
    	cout << "&d1:" << &d1 << endl;
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    

    编译运行的结果:
    确实调用了复制构造函数。

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor1
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(m1):0xbfbafbd0, i:1, this->iAge:1
    Demo(const Demo &d),this():0xbfbafbc8, &d_copy(m1):0xbfbafbd0
    &d1:0xbfbafbc8
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this():0xbfbafbc8
    ~Demo,this(m1):0xbfbafbd0
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    
    

    3. 第3种 Demo d1 = Demo(m1);

    copy_constructor2.cpp

    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo m1(1, "m1");
    	Demo d1 = Demo(m1);
    	cout << "&d1:" << &d1 << endl;
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    

    编译运行的结果:
    确实调用了复制构造函数。

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor2
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(m1):0xbfdfd890, i:1, this->iAge:1
    Demo(const Demo &d),this():0xbfdfd888, &d_copy(m1):0xbfdfd890
    &d1:0xbfdfd888
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this():0xbfdfd888
    ~Demo,this(m1):0xbfdfd890
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    4. 第4种 Demo *pDemo = new Demo(m1);

    copy_constructor3.cpp

    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo m1(1, "m1");
    	Demo *pDemo = new Demo(m1);
    	cout << "pDemo:" << pDemo << endl;
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    

    编译运行的结果:
    确实调用了复制构造函数。

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor3
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(m1):0xbf8bd8cc, i:1, this->iAge:1
    Demo(const Demo &d),this():0x8a24020, &d_copy(m1):0xbf8bd8cc
    pDemo:0x8a24020
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this(m1):0xbf8bd8cc
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    
    

    5. 第5种,func(Demo d_var)

    copy_constructor4.cpp

    void func(Demo d_var)
    {
    	cout << "func(Demo d_var)" << endl;
    }
    
    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo d1(1, "d1");
    	func(d1);
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    

    编译运行的结果:
    确实调用了复制构造函数。

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor4
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d1):0xbfbaa140, i:1, this->iAge:1
    Demo(const Demo &d),this():0xbfbaa138, &d_copy(d1):0xbfbaa140
    func(Demo d_var)
    ~Demo,this():0xbfbaa138
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this(d1):0xbfbaa140
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    6. 第6种,Demo func(),引发了很多思考

    copy_constructor5.cpp

    Demo func()
    {
    	Demo d1(1, "d1");
    	cout << "func()" << endl;
    	return d1;
    }
    
    
    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	func();
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    
    

    编译运行的结果:
    发现并没有调用复制构造函数,这是为什么呢?

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor5
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d1):0xbfc7e4a8, i:1, this->iAge:1
    func(Demo d_var)
    ~Demo,this(d1):0xbfc7e4a8
    ---------------结束--->公众号:梦悦foundation---------------
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    刚开始我以为是没有人使用它的返回值,这种情况如果我是写编译器的人肯定是会优化掉的。因为没有人使用返回值,就不用浪费一次复制构造函数执行的开销。
    所以我改了一下代码,改成下面这样。
    copy_constructor6.cpp

    	Demo d2 = func();
    	d2.Show(); //这是把成员变量都打印出来,看看d2的成员变量有没有被改变
    

    编译运行结果:
    可以看出来 d2这个对象确实和d1一样,但是却没有调用复制构造函数来完成这个工作,那是谁在起作用?

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ g++ -o copy_constructor5 copy_constructor5.cpp
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor5
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d1):0xbfe02298, i:1, this->iAge:1
    func()
    Show(),this(d1):0xbfe02298, this->iAge:1
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this(d1):0xbfe02298
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    先来看看原因,c++提供了一个返回优化,RVO(return value optimization),被g++进行优化了。

      -fno-elide-constructors
          The C++ standard allows an implementation to omit creating a temporary that is only used to initialize
         another object of the same type.  Specifying this option disables that optimization, and forces g++ to
          call the copy constructor in all cases.
    

    我们可以在编译的时候,指定选项 -fno-elide-constructors 来关闭 这个返回优化
    copy_constructor7.cpp
    g++ -fno-elide-constructors -o copy_constructor7 copy_constructor7.cpp

    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	func();
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    
    

    编译运行的结果:
    可以看出来,关闭掉返回优化,确实复制构造函数就调用了。

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor7
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d1):0xbff2a42c, i:1, this->iAge:1
    func()
    Demo(const Demo &d),this():0xbff2a468, &d_copy(d1):0xbff2a42c
    ~Demo,this(d1):0xbff2a42c
    ~Demo,this():0xbff2a468
    ---------------结束--->公众号:梦悦foundation---------------
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    但是,这不能够解释 Demo d2 = func(); 这条语句为什么会生效,因为它省略了复制构造函数这个临时对象的生成,那就不会调用复制构造函数,那是谁给d2赋值的呢??
    关于重载赋值运算符的知识
    P18-c++复制构造函数深度剖析介绍,详细的例子演示!
    这是个疑问,我也不知道,记录下来
    我本来以为是c++提供的默认的operator=()函数做的,但是我显示的提供可这个函数,发现也没有调用!
    这里也有两种情况,一种是初始化的时候,返回类对象,像下面这样

    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo d2 = func();
    	d2.Show();
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    

    另外一种是这样,给已存在的对象赋值

    Demo d2(2, "d2");
    d2 = func();
    

    这里也分别看看这两种情况的运行结果
    copy_constructor8.cpp 对应的是上面的第一种情况!
    新增加了 一个 operator=() 成员函数。

      /*
    	 author:梦悦foundation
    	 公众号:梦悦foundation
    	 可以在公众号获得源码和详细的图文笔记
     */
     
    #include <iostream>
    #include <typeinfo>
    #include <string>
     
    using namespace std;
    class Demo {
    private:
    	int iAge;
    	string var_name;
    public:
    	Demo() {
    		iAge = 0;
    		var_name = "temp";
    		cout << "Demo(), this(" << this->var_name << "):" << this << ", this->iAge:" << this->iAge << endl;
    	}
    	Demo(int i, string  name = "meng-yue") {
    		this->iAge = i;
    		this->var_name = name;
    		cout << "Demo(int i),this(" << this->var_name << "):" << this << ", i:" << i << ", this->iAge:" << this->iAge << endl;
    	}
    	Demo(const Demo & d_copy) {
    		cout << "Demo(const Demo &d),this(" << this->var_name << "):" << this << ", &d_copy(" << d_copy.var_name <<  "):" << &d_copy << endl;
    	}
    	
    	Demo & operator=(const Demo & d_var) {
    		cout << "operator=(const Demo&d_var),this(" << this->var_name << "):" << this << ", &d_var(" << d_var.var_name <<  "):" << &d_var;
    		cout << ", this->iAge:" << this->iAge << ", d_var.iAge:" << d_var.iAge << endl;
    	}
    	~Demo() {
    		cout << "~Demo,this(" << this->var_name << "):" << this << endl;
    	}
    	void Show() {
    		cout << "Show(),this(" << this->var_name << "):" << this << ", this->iAge:" << this->iAge << endl;;
    	}
    };
    
    Demo func()
    {
    	Demo d1(1, "d1");
    	cout << "func()" << endl;
    	return d1;
    }
    
    
    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo d2 = func();
    	d2.Show();
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    
    

    编译运行结果:

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ g++ -o copy_constructor8 copy_constructor8.cpp
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor8
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d1):0xbfaeb648, i:1, this->iAge:1
    func()
    Show(),this(d1):0xbfaeb648, this->iAge:1
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this(d1):0xbfaeb648
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    结果发现,既没有调用复制构造函数,也没有调用 operator=(),但是很神奇的是,d2 的值 跟d1 一模一样了。
    这个地方要留下一个疑问,是谁在默默付出??

    我们尝试将返回优化关闭掉去

    g++ -fno-elide-constructors -o copy_constructor8 copy_constructor8.cpp
    

    编译运行的结果:
    这个结果很有意思,对比一下之前没有关闭返回优化的,d2 的成员变量是都被赋值的(从d2.Show() 的输出能够看出来),
    Show(),this():0xbf917398, this->iAge:-1080986680 没有被赋值,都是空的。
    我们从头开始分析一下代码:
    首先调用 func(), 这个函数里面创建了一个 Demo对象 Demo d1(1, "d1");,所以打印了下面的构造函数。

    Demo(int i),this(d1):0xbf91735c, i:1, this->iAge:1
    

    接着就 return d1;, 我们关闭掉返回优化,可想而知,这需要一个临时变量来接收d1 这个类对象,因为d1 在执行完 func() 作用域就结束了。
    所以 return d1 就相当于下面这样一条语句

    Demo temp = d1;
    

    所以这个时候会调用赋值构造函数创建 temp这个临时对象,所以会有下面的打印

    Demo(const Demo &d),this():0xbf917390, &d_copy(d1):0xbf91735c
    

    结合复制构造函数的原型 Demo(const Demo & d_copy),d_copy 就是 要复制的 d1。
    这个临时对象temp的地址是0xbf917390,而且d_copy 的名字也确实是d1, 然后地址 是0xbf91735c ,这个可以与前面构造d1的时候的地址进一步确认Demo(int i),this(d1):0xbf91735c, i:1, this->iAge:1 地址是一模一样的。

    紧接着 d1就被析构了。所以代码就相当于变成了

    Demo d2 = temp;
    

    同理这会导致复制构造函数的调用,temp是复制构造函数的形参,从打印也能看出来, d_copy 的地址是 0xbf917390,也确实是这个临时变量temp的地址。

    Demo(const Demo &d),this():0xbf917398, &d_copy():0xbf917390
    

    d2 的地址是 0xbf917398。从最后的 d2.Show()打印能够对的上。
    不过因为关闭掉了返回优化,发现使用了复制构造函数,但是复制构造函数里面并没有做任何拷贝工作。所以 d2的成员变量的值都是空的。

    Show(),this():0xbf917398, this->iAge:-1080986680
    
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor8
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d1):0xbf91735c, i:1, this->iAge:1
    func()
    Demo(const Demo &d),this():0xbf917390, &d_copy(d1):0xbf91735c
    ~Demo,this(d1):0xbf91735c
    Demo(const Demo &d),this():0xbf917398, &d_copy():0xbf917390
    ~Demo,this():0xbf917390
    Show(),this():0xbf917398, this->iAge:-1080986680
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this():0xbf917398
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    copy_constructor9.cpp 演示的是上面的另一种情况,给已存在的对象赋值
    其他部分和copy_constructor9.cpp是一模一样的,只是更改了main()部分

    int main()
    {
    	cout << "---------------开始--->公众号:梦悦foundation---------------" << endl;
    	Demo d2(2, "d2");
    	d2 = func();
    	d2.Show();
    	cout << "---------------结束--->公众号:梦悦foundation---------------" << endl;
    	return 0;
    }
    

    编译运行的结果:
    发现赋值运算符确实调用了,因为这是给已有的对象赋值。
    而且这个地方你发现,operator=()是在d1还存活的时候运行的,你从打印能看出来

    func()
    operator=(const Demo&d_var),this(d2):0xbff7a750, &d_var(d1):0xbff7a748, this->iAge:2, d_var.iAge:1
    ~Demo,this(d1):0xbff7a748
    

    而且,这个打印相当于 d2.operator=(d1),调用完了 赋值函数,才析构掉d1的。

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ g++ -o copy_constructor9 copy_constructor9.cpp
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor9
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d2):0xbff7a750, i:2, this->iAge:2
    Demo(int i),this(d1):0xbff7a748, i:1, this->iAge:1
    func()
    operator=(const Demo&d_var),this(d2):0xbff7a750, &d_var(d1):0xbff7a748, this->iAge:2, d_var.iAge:1
    ~Demo,this(d1):0xbff7a748
    Show(),this(d2):0xbff7a750, this->iAge:2
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this(d2):0xbff7a750
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    那我们同样做个对比,再把返回优化给关闭掉,看看对比结果

    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ g++ -fno-elide-constructors -o copy_constructor9 copy_constructor9.cpp
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$ ./copy_constructor9
    ---------------开始--->公众号:梦悦foundation---------------
    Demo(int i),this(d2):0xbfeae33c, i:2, this->iAge:2
    Demo(int i),this(d1):0xbfeae2fc, i:1, this->iAge:1
    func()
    Demo(const Demo &d),this():0xbfeae334, &d_copy(d1):0xbfeae2fc
    ~Demo,this(d1):0xbfeae2fc
    operator=(const Demo&d_var),this(d2):0xbfeae33c, &d_var():0xbfeae334, this->iAge:2, d_var.iAge:134524916
    ~Demo,this():0xbfeae334
    Show(),this(d2):0xbfeae33c, this->iAge:2
    ---------------结束--->公众号:梦悦foundation---------------
    ~Demo,this(d2):0xbfeae33c
    book@book-desktop:~/meng-yue/c++/class_dynamic_memory/02$
    

    你发现,d1是在调用operator=()函数前就被析构了,取而代之的生成了一个临时对象,作为这个赋值函数的参数。
    源码资料路径
    在这里插入图片描述

    展开全文
  • 一、复制构造函数定义 复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。作用是用一个已知的对象去初始化同类型的新对象。 class 类名 { public: 类型(形参);//构造函数 类名(const 类名 &...

    一、复制构造函数定义

    • 复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。作用是用一个已知的对象去初始化同类型的新对象。
    class 类名
    {
    public:
    	类型(形参);//构造函数
    	类名(const 类名 &对象名);//复制构造函数
    //...
    };
    类名::类(const 类名 &对象名)//复制构造函数的实现
    { 函数体 }
    

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

    • 定义一个对象时,以本类另一个对象作为初始值,发生复制构造;
    • 如果函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造;
    • 如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化一个临时无名对象,传递给主调函数,此时发生复制构造。(这种情况也可以通过移动构造避免不必要的复制)

    三、隐含的复制构造函数

    • 如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个隐含的复制构造函数。
    • 这个构造函数执行的功能是:用初始值对象的每个数据成员,初始化将要建立的对象的对应数据成员。

    四、"=delete"

    如果不希望对象被复制构造:

    • C++98做法:将复制构造函数声明为private,并且不提供函数的实现。
    • C++11做法:用"=delete"指示编译器不生成默认复制构造函数。
    • 例:
    class Point{ //Point类的定义
    public:
    	Point(int xx=0, int yy=0){x = xx; y = yy;} //构造函数,内联
    	Point(const Point& p) = delete; //指示编译器不生成默认复制构造函数
    private:
    	int x, y; //私有数据
    };
    
    展开全文
  • 对于我来说,在写代码的时候能用得上复制构造函数的机会并不多,不过这并不说明复制构造函数没什么用,其实复制构造函数能解决一些我们常常会忽略的问题。为了说明复制构造函数作用,我先说说我们在编程时会遇到的...

    也许很多C++的初学者都知道什么是构造函数,但是对复制构造函数(copy constructor)却还很陌生。对于我来说,在写代码的时候能用得上复制构造函数的机会并不多,不过这并不说明复制构造函数没什么用,其实复制构造函数能解决一些我们常常会忽略的问题。

    为了说明复制构造函数作用,我先说说我们在编程时会遇到的一些问题。对于C++中的函数,我们应该很熟悉了,因为平常经常使用;对于类的对象,我们也很熟悉,因为我们也经常写各种各样的类,使用各种各样的对象;对于指针的操作,我们也不陌生吧?嗯,如果你还不了解上面三个概念的话,我想这篇文章不太适合你,不过看看也无碍^_^。我们经常使用函数,传递过各种各样的参数给函数,不过把对象(注意是对象,而不是对象的指针或对象的引用)当作参数传给函数的情况我们应该比较少遇见吧,而且这个对象的构造函数还涉及到一些内存分配的操作。嗯,这样会有什么问题呢?

    把参数传递给函数有三种方法,一种是值传递,一种是传地址,还有一种是传引用。前者与后两者不同的地方在于:当使用值传递的时候,会在函数里面生成传递参数的一个副本,这个副本的内容是按位从原始参数那里复制过来的,两者的内容是相同的。当原始参数是一个类的对象时,它也会产生一个对象的副本,不过在这里要注意。一般对象产生时都会触发构造函数的执行,但是在产生对象的副本时却不会这样,这时执行的是对象的复制构造函数。为什么会这样?嗯,一般的构造函数都是会完成一些成员属性初始化的工作,在对象传递给某一函数之前,对象的一些属性可能已经被改变了,如果在产生对象副本的时候再执行对象的构造函数,那么这个对象的属性又再恢复到原始状态,这并不是我们想要的。所以在产生对象副本的时候,构造函数不会被执行,被执行的是一个默认的构造函数。当函数执行完毕要返回的时候,对象副本会执行析构函数,如果你的析构函数是空的话,就不会发生什么问题,但一般的析构函数都是要完成一些清理工作,如释放指针所指向的内存空间。这时候问题就可能要出现了。假如你在构造函数里面为一个指针变量分配了内存,在析构函数里面释放分配给这个指针所指向的内存空间,那么在把对象传递给函数至函数结束返回这一过程会发生什么事情呢?首先有一个对象的副本产生了,这个副本也有一个指针,它和原始对象的指针是指向同块内存空间的。函数返回时,对象的析构函数被执行了,即释放了对象副本里面指针所指向的内存空间,但是这个内存空间对原始对象还是有用的啊,就程序本身而言,这是一个严重的错误。然而错误还没结束,当原始对象也被销毁的时候,析构函数再次执行,对同一块系统动态分配的内存空间释放两次是一个未知的操作,将会产生严重的错误。

    上面说的就是我们会遇到的问题。解决问题的方法是什么呢?首先我们想到的是不要以传值的方式来传递参数,我们可以用传地址或传引用。没错,这样的确可以避免上面的情况,而且在允许的情况下,传地址或传引用是最好的方法,但这并不适合所有的情况,有时我们不希望在函数里面的一些操作会影响到函数外部的变量。那要怎么办呢?可以利用复制构造函数来解决这一问题。复制构造函数就是在产生对象副本的时候执行的,我们可以定义自己的复制构造函数。在复制构造函数里面我们申请一个新的内存空间来保存构造函数里面的那个指针所指向的内容。这样在执行对象副本的析构函数时,释放的就是复制构造函数里面所申请的那个内存空间。

    除了将对象传递给函数时会存在以上问题,还有一种情况也会存在以上问题,就是当函数返回对象时,会产生一个临时对象,这个临时对象和对象的副本性质差不多。

    拷贝构造函数,经常被称作X(X&),是一种特殊的构造函数,他由编译器调用来完成一些基于同一类的其他对象的构件及初始化。它的唯一的一个参数(对象的引用)是不可变的(因为是const型的)。这个函数经常用在函数调用期间于用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。

    在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。

    1). 一个对象以值传递的方式传入函数体

    2). 一个对象以值传递的方式从函数返回

    3). 一个对象需要通过另外一个对象进行初始化

    以上的情况需要拷贝构造函数的调用。如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作赋共同实现的。描述拷贝构造函数和赋值运算符的异同的参考资料有很多。

    拷贝构造函数不可以改变它所引用的对象,其原因如下:当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的被调用来生成函数中的对象。如果一个对象是被传入自己的拷贝构造函数,它的拷贝构造函数将会被调用来拷贝这个对象这样复制才可以传入它自己的拷贝构造函数,这会导致无限循环。

    除了当对象传入函数的时候被隐式调用以外,拷贝构造函数在对象被函数返回的时候也同样的被调用。换句话说,你从函数返回得到的只是对象的一份拷贝。但是同样的,拷贝构造函数被正确的调用了,你不必担心。

    如果在类中没有显式的声明一个拷贝构造函数,那么,编译器会私下里为你制定一个函数来进行对象之间的位拷贝(bitwise copy)。这个隐含的拷贝构造函数简单的关联了所有的类成员。许多作者都会提及这个默认的拷贝构造函数。注意到这个隐式的拷贝构造函数和显式声明的拷贝构造函数的不同在于对于成员的关联方式。显式声明的拷贝构造函数关联的只是被实例化的类成员的缺省构造函数除非另外一个构造函数在类初始化或者在构造列表的时候被调用。

    拷贝构造函数是程序更加有效率,因为它不用再构造一个对象的时候改变构造函数的参数列表。设计拷贝构造函数是一个良好的风格,即使是编译系统提供的帮助你申请内存默认拷贝构造函数。事实上,默认拷贝构造函数可以应付许多情况。

    附另外一篇关于复制构造函数的文章:

    对一个简单变量的初始化方法是用一个常量或变量初始化另一个变量,例如:

    int m = 80;

    int n = m;

    我们已经会用构造函数初始化对象,那么我们能不能象简单变量的初始化一样,直接用一个对象来初始化另一个对象呢?答案是肯定的。我们以前面定义的Point类为例:

    Point pt1(15, 25);

    Point pt2 = pt1;

    后一个语句也可以写成:

    Point pt2( pt1);

    它是用pt1初始化pt2,此时,pt2各个成员的值与pt1各个成员的值相同,也就是说,pt1各个成员的值被复制到pt2相应的成员当中。在这个初始化过程当中,实际上调用了一个复制构造函数。当我们没有显式定义一个复制构造函数时,编译器会隐式定义一个缺省的复制构造函数,它是一个内联的、公有的成员,它具有下面的原型形式:

    Point:: Point (const Point &);

    可见,复制构造函数与构造函数的不同之处在于形参,前者的形参是Point对象的引用,其功能是将一个对象的每一个成员复制到另一个对象对应的成员当中。

    虽然没有必要,我们也可以为Point类显式定义一个复制构造函数:

    Point:: Point (const Point &pt)

    {

    xVal=pt. xVal;

    yVal=pt. yVal;

    }

    如果一个类中有指针成员,使用缺省的复制构造函数初始化对象就会出现问题。为了说明存在的问题,我们假定对象A与对象B是相同的类,有一个指针成员,指向对象C。当用对象B初始化对象A时,缺省的复制构造函数将B中每一个成员的值复制到A的对应的成员当中,但并没有复制对象C。也就是说,对象A和对象B中的指针成员均指向对象C,实际上,我们希望对象C也被复制,得到C的对象副本D。否则,当对象A和B销毁时,会对对象C的内存区重复释放,而导致错误。为了使对象C也被复制,就必须显式定义复制构造函数。下面我们以string类为例说明,如何定义这个复制构造函数。

    class String

    {

    public:

    String(); //构造函数

    String(const String &s); //复制构造函数

    ~String(); //析构函数

    // 接口函数

    void set(char const *data);

    char const *get(void);

    private:

    char *str; //数据成员ptr指向分配的字符串

    };

    String ::String(const String &s)

    {

    str = new char[strlen(s.str) + 1];

    strcpy(str, s.str);

    }

    我们也常用无名对象初始化另一个对象,例如:

    Point pt = Point(10, 20);

    类名直接调用构造函数就生成了一个无名对象,上式用左边的无名对象初始化右边的pt对象。

    构造函数被调用通常发生在以下三种情况,第一种情况就是我们上面看到的:用一个对象初始化另一个对象时;第二种情况是当对象作函数参数,实参传给形参时;第三种情况是程序运行过程中创建其它临时对象时。下面我们再举一个例子,就第二种情况和第三种情况进行说明:

    Point foo(Point pt)

    {

    return pt;

    }

    void main()

    {

    Point pt1 = Point(10, 20);

    Point pt2;

    pt2=foo(pt);

    }

    在main函数中调用foo函数时,实参pt传给形参pt,将实参pt复制给形参pt,要调用复制构造函数,当函数foo返回时,要创建一个pt的临时对象,此时也要调用复制构造函数。

    缺省的复制构造函数  在类的定义中,如果没有显式定义复制构造函数,C++编译器会自动地定义一个缺省的复制构造函数。下面是使用复制构造函数的一个例子:

    例10-12

    #include

    #include

    class withCC

    {

    public:

    withCC(){}

    withCC(const withCC&)

    {

    cout<

    }

    };

    class woCC

    {

    enum{bsz = 100};

    char buf[bsz];

    public:

    woCC(const char* msg = 0)

    {

    memset(buf, 0, bsz);

    if(msg) strncpy(buf, msg, bsz);

    }

    void print(const char* msg = 0)const

    {

    if(msg) cout<

    cout<

    }

    };

    class composite

    {

    withCC WITHCC;

    woCC WOCC;

    public:

    composite() : WOCC("composite()"){}

    void print(const char* msg = 0)

    {

    WOCC.print(msg);

    }

    };

    void main()

    {

    composite c;

    c.print("contents of c");

    cout<

    composite c2 = c;

    c2.print("contents of c2");

    }   类withCC有一个复制构造函数,类woCC和类composite都没有显式定义复制构造函数。如果在类中没有显式定义复制构造函数,则编译器将自动地创建一个缺省的构造函数。不过在这种情况下,这个构造函数什么也不作。

    类composite既含有withCC类的成员对象又含有woCC类的成员对象,它使用无参的构造函数创建withCC类的对象WITHCC(注意内嵌的对象WOCC的初始化方法)。

    在main()函数中,语句:

    composite c2 = c;

    通过对象C初始化对象c2,缺省的复制构造函数被调用。

    最好的方法是创建自己的复制构造函数而不要指望编译器创建,这样就能保证程序在我们自己的控制之下。

    展开全文
  • 构造函数模式用于定义实例属性,而原型模式用域定义方法和共享的属性 动态原型模式 把信息都封装在构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数原型的优点,添加if-----...
  • 构造函数原型和实例之间的关系:每个构造函数【SuperType】都有一个原型对象【prototype】,原型有一个属性【constructor】指回构造函数,而实例有一个内部指针【_proto_】指向原型。即如下图所示: 在这里要记住...
  • 每一个函数拥有原型(prototype)属性,如果该函数充当构造函数去 new 实例,则会构成一条原型链,每个实例成员都可以使用原型上的属性和方法 function Person() {} Person.prototype.say = function() { console....
  • 复制构造函数具有以下常规函数原型: ClassName(const ClassName&old_obj); 以下是复制构造函数的一个简单示例: #include<iostream> using namespace std; class Point { private: int x, y; ...
  • 复制构造函数

    千次阅读 2021-03-18 21:50:24
    复制构造函数 是用来将一个对象复制到新创建的对象当中,是内容的拷贝, 函数原型通常如下 ClassName(const ClassName &); 何时调用复制构造函数 新建一个对象,并将其初始化为现有同类对象时,复制构造函数将会...
  • // 不能通过对象来访问 </script> - prototype(构造函数原型) 【实现函数共享 解决构造函数的内存浪费】 【原型,时一个对象,我们也称prototype为原型对象】 - 对象原型 __ proto __ 【对象都会有一个属性__ ...
  • 构造函数原型

    2021-06-29 13:13:41
    title: 构造函数原型 date: 2021-06-19 17:02:49 tags: 构造函数原型 目标 能够使用构造函数创建对象 能够说出圆形的作用 能够说出访问对象成员的规则 能够使用ES5新增的一些方法 1. 构造函数原型 1.1 概述 ...
  • 因此,在前面的例子中,复制构造函数原型就应该是下面这个样子的:NumberArray :: NumberArray(NumberArray&obj)此复制构造函数通过在复制之前为新对象的指针分配单独的内存来避免默认复制构造函数的问题:...
  • 拷贝构造函数与运算符重载拷贝构造函数引出拷贝构造函数运算符重载引出拷贝构造函数 拷贝构造函数引出 先给出日期类的定义: class Date { public: Date(int year=1900,int month=1, int day=1) { _year = ...
  • 原文:前端基础进阶(九):详解面向对象、构造函数原型原型链如果要我总结一下学习前端以来我遇到了哪些瓶颈,那么面向对象一定是第一个毫不犹豫想到的。尽管我现在对于面向对象有了一些的了解,但是当初的那种...
  • 通过C++拷贝构造函数一节的学习我们知道,拷贝构造函数的实现原理很简单,就是为新对象复制一份和其它对象一模一样的数据。 需要注意的是,当类中拥有指针类型的成员变量时,拷贝构造函数中需要以深拷贝(而非浅...
  • C++中的五种构造函数

    2021-05-12 16:55:53
    C++中的构造函数可以分为4类:默认构造函数、普通构造函数、拷贝构造函数、转换构造函数。 (1)默认构造函数。 未提供显式初始值时,用来穿件对象的构造函数。...复制构造函数在以下三种情况下会被调用。
  • 什么时候调用复制构造函数默认构造函数拷贝构造函数何时调用拷贝构造函数 默认构造函数 如果用户没有定义构造函数,C++将创建默认构造函数。例如,创建COriginal类,但没有提供任何构造函数,则编译器将提供下述默认...
  • 原型链继承是比较常见的继承方式之一,其中涉及的构造函数原型和实例,三者之间存在着一定的关系,即每一个构造函数都有一个原型对象,原型对象又包含一个指向构造函数的指针,而实例则包含一个原型对象的指针。...
  • function Father(name,age){ this.name = name this.age = age } // 共有的方法,定义到构造函数原型上 Father.prototype = { // 用这种对象的方式给原型复制的话,必须手动的将constructor这个属性值,设置为当前...
  • 1.js中的构造函数的写法 function Person(){}; //定义一个构造函数 Person.prototype.name="abc"; //原型对象中添加属性 Person.prototype.age = 18; var p1 = new Person(); //实例化 var p2 = new Person(); ...
  • 1 构造函数创建对象创建对象:var obj = new Object(); 使用new关键字调用的为构造函数,用于创建新的对象 向对象中可保存的内容有属性 obj.name = ‘XX’ 属性的定义及赋值 使用时,对象.属性名 获
  • 构造函数二. 析构函数三. 拷贝构造函数1.浅拷贝2.深拷贝四. 赋值函数 在C++中,对于一个类,C++的编译器都会为这个类提供四个默认函数,分别是: A() //默认构造函数 ~A() //默认析构函数 A(const A&) //...
  • 四、原型 虽然构造函数解决了判断实例类型的问题,但是,说到底,还是一个对象的复制过程。跟工厂模式颇有相似之处。也就是说,当我们声明了100个person对象,那么就有100个getName方法被重新生成。 这里的每一个...
  • 对于我来说,在写代码的时候能用得上复制构造函数的机会并不多,不过这并不说明复制构造函数没什么用,其实复制构造函数能解决一些我们常常会忽略的问题。 为了说明复制构造函数作用,我先说说我们在编程时会遇到的...
  • 下面展示一些 内联代码片。 //工厂模式创建对象 使得代码更像一个整体 但是...//谁调用这个函数,this的指向就为谁 console.log(this.name); } } } var p1 = person(“zhangsan”,14); var p2 = person(“lisi”,12)
  • 课程内容:对象的创建与复制构造函数原型函数DOM与节点的操作(1)DOM与节点的操作(2)7月10日作业1. 写一个构造函数来创建对象实例html>构造函数作业//创建一个构造函数//创建一个构造函数//创建一个构造函数//...
  • this指向对象中的this原型链中的this构造函数中的thiscall&apply中的thisbind中的thisDOM 事件处理函数中的 this & 内联事件中的 thisDOM事件处理函数内联函数setTimeout & setInterval箭头函数中的 ...
  • js继承之构造函数继承 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" ...
  • 文章目录前言一、什么是盗用构造函数?二、使用实例三、参数传递四、盗用构造函数的问题所在五、总结 前言 写本《JavaScript简餐》系列文章的目的是记录在阅读学习《JavaScript高级程序设计(第4版)》一书时出现...
  • 构造函数使用new的类

    2021-03-14 12:34:39
    如果使用new运算符分配类成员指向的内存,在设计时应该采用一些预防措施: ...如果构造函数使用的是new [] ,则析构函数也应使用delete[], 如果构造函数使用的new,则析构函数也应该使用delete. 4、

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 52,210
精华内容 20,884
关键字:

复制构造函数的原型