精华内容
下载资源
问答
  • 构造函数

    2019-09-11 23:05:44
    1.什么构造函数 在JavaScript中,用 new 关键字来调用的函数,称为构造函数。首字母一般大写; 2.为什么要用构造函数 如下: 像下面这样,我们可以把每一位同学的信息当做一个对象来处理。但是,我们会发现,...

    1.什么是构造函数
    在JavaScript中,用 new 关键字来调用的函数,称为构造函数。首字母一般大写;

    2.为什么要用构造函数
    如下:
    像下面这样,我们可以把每一位同学的信息当做一个对象来处理。但是,我们会发现,我们重复地写了很多无意义的代码。比如 name、age、gender、hobby 。如果这个班上有60个学生,我们得重复写60遍。

       var p1 = { name: 'zs', age: 6, gender: '男', hobby: 'basketball' };
       var p2 = { name: 'ls', age: 6, gender: '女', hobby: 'dancing' };
       var p3 = { name: 'ww', age: 6, gender: '女', hobby: 'singing' };
       var p4 = { name: 'zl', age: 6, gender: '男', hobby: 'football' };
    

    这个时候,构造函数的优势就体现出来了。我们发现,虽然每位同学都有 name、gender、hobby这些属性, 但它们都是不同的,那我们就把这些属性当做构造函数的参数传递进去。而由于都是一年级的学生,age 基本都是6岁,所以我们就可以写死,遇到特殊情况再单独做处理即可。此时,我们就可以创建以下的函数

    	function Person (name,gender,hobby) {
              this.name = name;
              this.gender = gender;
              this.hobby = hobby;
              this.age = 6;
        }
    

    创建上面的函数后,可以通过 new 关键字调用, 也就是说通过构造函数来创建对象;

         var p1 = new Person ('zs','男','basketball');
         var p2 = new Person ('ls','女','dancing');
         var p3 = new Person ('ww','女','singing');
         var p4 = new Person ('zl','男','football');
    

    在使用对象字面量创建一系列同一类型的对象时,这些对象可能具有一些相似的特征(属性)和行为(方法), 此时会产生很多重复的代码,而使用构造函数就可以实现代码复用。

    3.构造函数的执行过程
    当 new 关键字调用时,会创建一个新的空间 如下:下图

         function Person (name,gender,hobby) {
                this.name = name;      
                this.gender = gender;
                this.hobby = hobby;
                this.age = 6;
                console.log(this);      
          }
          
          var p2 = new Person('ls', '女', 'dancing');  // 创建一个新的内存 #f2 
          var p3 = new Person('ww', '女', 'singing');  // 创建一个新的内存 #f3
    

    在这里插入图片描述
    每当创建一个实例的时候,就会创建一个新的内存空间(#f2, #f3),创建 #f2 的时候,函数体内部的 this 指向 #f2, 创建 #f3 的时候,函数体内部的 this 指向 #f3

    4、构造函数的返回值

    01基本类型的返回值 ,还是返回 this (this的指向是 Person -> 创建一个新的内存 )
    
         function Person() {
               this.age = 28;
               return 50
         }
    
         var p = new Person();
         console.log(p.age);    //28
    

    如果是普通函数调用 而不是 构造函数的话 返回值就是50;

    02:	引用类型(对象)的返回值,最终返回该对象
    
         function Person1 () {
       	 	   this.gender = '男';
               return {gender: '女人'};
         }
         var q1 = new Person1 ();
         console.log(q1.gender); // 女人
    
    展开全文
  • JavaScript 中的构造函数

    千次阅读 多人点赞 2018-11-10 20:08:26
    但是,在JavaScript语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。 以下的内容会分为如下细节: 1.对象的概念 2.构造函数 3.new 命令  3.1:基本原理  3.2:...

     

    典型的面向对象编程语言(比如C++和Java),存在“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,在JavaScript语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

    以下的内容会分为如下细节:

    1.对象的概念

    2.构造函数

    3.new 命令

      3.1:基本原理

      3.2:基本用法

    1.对象的概念

      “面向对象编程”(Object Oriented Programming,缩写为OOP)是目前主流的编程范式。它的核心思想是将真实世界中各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。

      在Javascript的重要数据类型-对象这篇文章中,提到了js中对象的一些基本知识,比如说对象的创建,对象的引用,对象的属性等等。如果没有掌握对象的基础知识,请移步Javascript的重要数据类型-对象

      在有了对象的基础知识之后,对js中对象做一个简单的总结。如下:

      a:对象是单个实物的抽象。

      b:对象是一个容器,封装了‘属性’和‘方法’。

      一本书、一辆汽车、一个人都可以是“对象”。当实物被抽象成“对象”,实物之间的关系就变成了“对象”之间的关系,从而就可以模拟现实情况,针对“对象”进行编程。

      所谓属性,就是对象的一种状态;所谓方法,就是对象的一种行为。

      比如说,可以把动物抽象为animal对象,属性记录的就是哪一种动物,以及该动物的大小和颜色等。方法表示该动物的某种行为(奔跑,猎食,交配,休息等等)。

    2.构造函数

      ‘面向对象编程’的第一步,就是要生成对象。而js中面向对象编程是基于构造函数(constructor)和原型链(prototype)的。

      前面说过,“对象”是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后“对象”根据这个模板生成。

      js语言中使用构造函数(constructor)作为对象的模板。所谓构造函数,就是提供一个生成对象的模板,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。

      看一下构造函数的基本结构。

    1     var Keith = function() {
    2         this.height = 180;
    3     };
    4     //两种写法相同。
    5     function Keith() {
    6         this.height = 180;
    7     }

      上面代码中,Keith就是构造函数,它提供模板,用来生成对象实例。为了与普通函数区别,构造函数名字的第一个字母通常大写。

      构造函数的三大特点:

      a:构造函数的函数名的第一个字母通常大写。

      b:函数体内使用this关键字,代表所要生成的对象实例。

      c:生成对象的时候,必须使用new命令来调用构造函数。

    3.new 命令

      3.1:基本原理

      new命令的作用,就是执行一个构造函数,并且返回一个对象实例。使用new命令时,它后面的函数调用就不是正常的调用,而是依次执行下面的步骤。

      a:创建一个空对象,作为将要返回的对象实例。

      b:将空对象的原型指向了构造函数的prototype属性。

      c:将空对象赋值给构造函数内部的this关键字。

      d:开始执行构造函数内部的代码。

      也就是说,构造函数内部,this指向的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。构造函数之所谓构造函数,意思是这个函数的目的就是操作一个空对象(即this对象),将其构造为需要的样子。

      以上是new命令的基本原理,这个很重要。以下会用具体实例来验证该原理的过程。

      3.2:基本用法

      new命令的作用,就是调用一个构造函数,并且返回一个对象实例。

    1     function Keith() {
    2         this.height = 180;
    3     }
    4 
    5     var boy = new Keith();
    6     console.log(boy.height);  //180

      上面代码中通过new命令,让构造函数Keith生成一个对象实例,并赋值给全局变量boy。这个新生成的对象实例,从构造函数Keith中继承了height属性。也就说明了这个对象实例是没有height属性的。在new命令执行时,就代表了新生成的对象实例boy。this.height表示对象实例有一个height属性,它的值是180。

      使用new命令时,根据需要,构造函数也可以接受参数。

     1     function Person(name, height) {
     2         this.name = name;
     3         this.height = height;
     4     }
     5 
     6     var boy = new Person('Keith', 180);
     7     console.log(boy.name); //'Keith'
     8     console.log(boy.height); //180
     9 
    10     var girl = new Person('Samsara', 160);
    11     console.log(girl.name); //'Samsara'
    12     console.log(girl.height); //160

      用以上的一个例子,来对构造函数的特点和new基本原理进行一个梳理。

      上面代码中,首先,我们创建了一个构造函数Person,传入了两个参数name和height。构造函数Person内部使用了this关键字来指向将要生成的对象实例。

      然后,我们使用new命令来创建了两个对象实例boy和girl。

      当我们使用new来调用构造函数时,new命令会创建一个空对象boy,作为将要返回的实例对象。接着,这个空对象的原型会指向构造函数Person的prototype属性。也就是boy.prototype===Person.prototype的。要注意的是空对象指向构造函数Person的prototype属性,而不是指向构造函数本身。然后,我们将这个空对象赋值给构造函数内部的this关键字。也就是说,让构造函数内部的this关键字指向一个对象实例。最后,开始执行构造函数内部代码。

      因为对象实例boy和girl是没有name和height属性的,所以对象实例中的两个属性都是继承自构造函数Person中的。这也就说明了构造函数是生成对象的函数,是给对象提供模板的函数。

      一个问题,如果我们忘记使用new命令来调用构造函数,直接调用构造函数了,会发生什么?

      这种情况下,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this这时代表全局对象,将造成一些意想不到的结果。

    1     function Keith() {
    2         this.height = 180;
    3     }
    4 
    5     var person = Keith();
    6     console.log(person.height); //TypeError: person is undefined
    7     console.log(window.height); //180

      上面代码中,当在调用构造函数Keith时,忘记加上new命令。结果是this指向了全局作用域,height也就变成了全局变量。而变量person变成了undefined。

      因此,应该非常小心,避免出现不使用new命令、直接调用构造函数的情况。

      为了保证构造函数必须与new命令一起使用,一个解决办法是,在构造函数内部使用严格模式,即第一行加上use strict

    1     function Person(name, height) {
    2         'use strict';
    3         this.name = name;
    4         this.height = height;
    5     }
    6     var boy = Person();
    7     console.log(boy) //TypeError: name is undefined

      上面代码的Person为构造函数,use strict命令保证了该函数在严格模式下运行。由于在严格模式中,函数内部的this不能指向全局对象。如果指向了全局,this默认等于undefined,导致不加new调用会报错(JavaScript不允许对undefined添加属性)。

      另一个解决办法,是在构造函数内部判断是否使用new命令,如果发现没有使用,则直接返回一个实例对象。

    1     function Person(name, height) {
    2     if (!(this instanceof Person)) {
    3             return new Person(name, height);
    4         }
    5         this.name = name;
    6         this.height = height;
    7     }
    8     var boy = Person('Keith');
    9     console.log(boy.name) //'Keith'

      上面代码中的构造函数,不管加不加new命令,都会得到同样的结果。

      如果构造函数内部有return语句,而且return后面跟着一个复杂数据类型(对象,数组等),new命令会返回return语句指定的对象;如果return语句后面跟着一个简单数据类型(字符串,布尔值,数字等),则会忽略return语句,返回this对象。

     1     function Keith() {
     2         this.height = 180;
     3         return {
     4             height: 200
     5         };
     6     }
     7     var boy = new Keith();
     8     console.log(boy.height); //200
     9 
    10     function Keith() {
    11         this.height = 100;
    12         return 200;
    13     }
    14     var boy = new Keith();
    15     console.log(boy.height); //100

      另一方面,如果对普通函数(内部没有this关键字的函数)使用new命令,则会返回一个空对象。

    1     function Keith() {
    2         return 'this is a message';
    3     }
    4     var boy = new Keith();
    5     console.log(boy); // Keith {}

      上面代码中,对普通函数Keith使用new命令,会创建一个空对象。这是因为new命令总是返回一个对象,要么是实例对象,要么是return语句指定的对象或数组。本例中,return语句返回的是字符串,所以new命令就忽略了该语句。

    完。

    转载掘金:https://juejin.im/entry/584a1c98ac502e006c5d63b8

    转载请注明出处:www.cnblogs.com/Uncle-Keith…

    展开全文
  • 了解有关Java中构造函数之间差异的更多信息。

    原文链接·:https://dzone.com/articles/explicit-no-arguments-constructor-vs-default-const

    大多数刚接触Java的开发人员很快就会知道,当他们没有指定至少一个显式构造函数时,他们的Java类会隐式创建一个“ 默认构造函数 ” (由javac创建)。8.8.9节中的Java语言规范简洁地指出,“如果一个类不包含任何构造函数声明,那么默认的构造函数是隐式声明。” 该部分进一步描述了隐式创建的默认构造函数的特征,包括它没有参数,没有子句,并且调用其超类的构造函数,类似地不接受任何参数。Java开发人员可以明确地选择throws实现一个类似于默认构造函数的无参数构造函数(例如不接受任何参数并且没有throws子句)。在这篇文章中,我看一下开发人员可能决定实现显式无参数构造函数而不是依赖隐式默认构造函数的一些原因。

    明确指定无参数构造函数的几个原因

    排除类的实例化
    实现显式无参数构造函数的一个常见原因是阻止使用public可访问性隐式创建默认构造函数。如果类具有其他显式构造函数(接受参数),则这是不必要的步骤,因为任何显式构造函数的存在都将阻止生成隐式默认构造函数。但是,如果不存在其他显式构造函数(例如在具有所有static方法的“实用程序”类中),则可以通过实现具有private访问权限的显式无参数构造函数来排除隐式默认构造函数。第8.8.10在的Java语言规范描述了所有的private显式的构造,以防止一类的实例。

    通过Builder或静态初始化工厂强制类实例化
    显式实现private无参数构造函数的另一个原因是通过静态初始化工厂方法或构造函数而不是构造函数强制实例化该类的对象。Effective Java(第三版)的前两项概述了使用静态初始化工厂方法和构建器而不是直接使用构造函数的优点。

    需要多个构造函数,包括无参数构造函数
    实现一个可能与上面讨论的原因相同或甚至更常见的无参数构造函数的一个显而易见的原因是需要一个无参数构造函数,但是期望参数的构造函数也是如此。在这种情况下,由于存在期望参数的其他构造函数,因此必须显式创建无参数构造函数,因为永远不会为已具有一个或多个显式构造函数的类隐式创建默认构造函数。

    使用Javadoc构建文档对象
    显式实现无参数构造函数而不是依赖于隐式创建的默认构造函数的另一个原因是在构造函数上表达Javadoc注释。这是JDK-8224174(“java.lang.Number有一个默认构造函数”)的陈述理由,它现在是JDK 13的一部分,也用当前未解析的JDK-8071961表示(“当默认构造函数为时,添加javac lint警告”创建“)。最近编写的CSR JDK-8224232(“java.lang.Number有一个默认构造函数”)详细阐述了这一点:“默认构造函数不适用于记录良好的API。”

    明确过度隐性的偏好
    一些开发人员通常喜欢隐式创建的显式规范。Java中有几个区域可以在显式规范或隐式对应项之间进行选择。如果开发人员重视交互方面或假定显式构造函数具有更高的可读性,那么开发人员可能更喜欢显式的无参数构造函数而不是隐式构造函数。

    使用显式无参数替换默认构造函数JDK中的构造函数
    在JDK中有一些情况,其中隐式默认构造函数已被显式无参数构造函数替换。这些包括以下内容:

    在JDK 9中解决的JDK-8071959(“java.lang.Object使用隐式默认构造函数”)用一个显式的无参数构造函数替换了java.lang.Object的“默认构造函数”。阅读这个问题的“描述”让我微笑:“当修改java.lang.Object(JDK-8071434)上的一些文档时,注意到该类确实没有有一个显式的构造函数,而是依赖于javac来创建一个隐式的默认构造函数。多么尴尬!“
    JDK-8177153(“LambdaMetafactory具有默认构造函数”),在JDK 9中解决,用显式(和private)无参数构造函数替换了隐式默认构造函数。
    JDK-8224174(“java.lang.Number有一个默认构造函数”),计划用于JDK 13,将用一个显式的无参数构造函数替换java.lang.Number的隐式默认构造函数。
    关于默认构造函数的潜在javac lint警告
    有一天javac可能会有一个可用的lint警告来指出带有默认构造函数的类。JDK-8071961(“创建默认构造函数时添加javac lint警告”)(当前不是任何特定JDK版本的目标),声明:“ JLS部分8.8.9文档,如果类没有声明至少一个构造函数,默认情况下,编译器会生成一个构造函数。虽然这个策略可能很方便,但对于正式类来说,如果没有其他原因,默认构造函数将没有javadoc,那么这是一个糟糕的编程习惯。使用默认构造函数可能是合理的javac lint警告。“

    结论

    依赖于在编译时创建的默认构造函数绝对是方便的,但是在某些情况下,即使不需要显式规范,也可以优先显式指定无参数构造函数。

    (想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程等待你来学习。完全免费哦! )

    展开全文
  • 请先记住以下的警告,在阅读正文时就会多心:如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类String 的两个...

    拷贝构造函数和赋值构造函数的异同
    由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。请先记住以下的警告,在阅读正文时就会多心:如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类String 的两个对象a,b 为例,假设a.m_data 的内容为“hello”,b.m_data 的内容为“world”。现将a 赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。这将造成三个错误:一是b.m_data 原有的内存没被释放,造成内存泄露;二是b.m_data 和a.m_data 指向同一块内存,a 或b 任何一方变动都会影响另一方;三是在对象被析构时,m_data 被释放了两次。拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。以下程序中,第三个语句和第四个语句很相似,你分得清楚哪个调用了拷贝构造函数,哪个调用了赋值函数吗?
      String a(“hello”);
      String b(“world”);
      String c = a; // 调用了拷贝构造函数,最好写成 c(a);
      c = b; // 调用了赋值函数
      本例中第三个语句的风格较差,宜改写成String c(a) 以区别于第四个语句。
      类String 的拷贝构造函数与赋值函数
      // 拷贝构造函数
      String::String(const String &other)
      {
      // 允许操作other 的私有成员m_data
      int length = strlen(other.m_data);
      m_data = new char[length+1];
      strcpy(m_data, other.m_data);
      }
      // 赋值函数
      String & String::operator =(const String &other)
      {
      // (1) 检查自赋值
      if(this == &other)
      return *this;
      // (2) 释放原有的内存资源
      delete [] m_data;
      // (3)分配新的内存资源,并复制内容
      int length = strlen(other.m_data);
      m_data = new char[length+1];
      strcpy(m_data, other.m_data);
      // (4)返回本对象的引用
      return *this;
      }
      类String 拷贝构造函数与普通构造函数的区别是:在函数入口处无需与NULL 进行比较,这是因为“引用”不可能是NULL,而“指针”可以为NULL。类String 的赋值函数比构造函数复杂得多,分四步实现:
      (1)第一步,检查自赋值。你可能会认为多此一举,难道有人会愚蠢到写出 a = a 这样的自赋值语句!的确不会。但是间接的自赋值仍有可能出现,例如
      // 内容自赋值
      b = a;
      …
      c = b;
      …
      a = c;
      // 地址自赋值
      b = &a;
      …
      a = *b;
      也许有人会说:“即使出现自赋值,我也可以不理睬,大不了化点时间让对象复制自己而已,反正不会出错!”他真的说错了。看看第二步的delete,自杀后还能复制自己吗?所以,如果发现自赋值,应该马上终止函数。注意不要将检查自赋值的if 语句
      if(this == &other)
      错写成为
      if( *this == other)
      (2)第二步,用delete 释放原有的内存资源。如果现在不释放,以后就没机会了,将造成内存泄露。
      (3)第三步,分配新的内存资源,并复制字符串。注意函数strlen 返回的是有效字符串长度,不包含结束符‘\0’。函数strcpy 则连‘\0’一起复制。
      (4)第四步,返回本对象的引用,目的是为了实现象 a = b = c 这样的链式表达。注意不要将 return *this 错写成 return this 。那么能否写成return other 呢?效果不是一样吗?不可以!因为我们不知道参数other 的生命期。有可能other 是个临时对象,在赋值结束后它马上消失,那么return other 返回的将是垃圾。
      偷懒的办法处理拷贝构造函数与赋值函数
      如果我们实在不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,怎么办?
      偷懒的办法是:只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。
      例如:
      class A
      { …
      private:
      A(const A &a); // 私有的拷贝构造函数
      A & operator =(const A &a); // 私有的赋值函数
      };
      如果有人试图编写如下程序:
      A b(a); // 调用了私有的拷贝构造函数
      b = a; // 调用了私有的赋值函数
      编译器将指出错误,因为外界不可以操作A 的私有函数。



    一、
    拷贝构造,是一个的对象来初始化一边内存区域,这边内存区域就是你的新对象的内存区域赋值运算,对于一个已经被初始化的对象来进行operator=操作
    class    A;     
    A   a;  
    A   b=a;    //拷贝构造函数调用  
    //或  
    A   b(a);    //拷贝构造函数调用  
    ///     
    A   a;  
    A   b;  
    b =a;    //赋值运算符调用   

    你只需要记住,在C++语言里,  
    String    s2(s1);  
    String    s3    =    s1;  
    只是语法形式的不同,意义是一样的,都是定义加初始化,都调用拷贝构造函数。

    二、
    一般来说是在数据成员包含指针对象的时候,应付两种不同的处理需求的 一种是复制指针对象,一种是引用指针对象 copy大多数情况下是复制,=则是引用对象的     
    例子:  
       class    A  
       {  
              int    nLen;  
              char    *    pData;  
       }  
       显然  
       A    a,    b;  
       a=b的时候,对于pData数据存在两种需求  
       第一种copy  
           a.pData    =    new    char    [nLen];  
           memcpy(a.pData,    b.pData,    nLen);  
       另外一种(引用方式):  
           a.pData    =    b.pData  
       
       通过对比就可以看到,他们是不同的  
       往往把第一种用copy使用,第二种用=实现
       你只要记住拷贝构造函数是用于类中指针,对象间的COPY  

    三、
       和拷贝构造函数的实现不一样    
       拷贝构造函数首先是一个构造函数,它调用的时候产生一个对象,是通过参数传进来的那个对象来初始化,产生的对象。  
       operator=();是把一个对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检查一下两个对象是不是同一个对象,如果是的话就不做任何操作。



    还要注意的是拷贝构造函数是构造函数,不返回值   

       而赋值函数需要返回一个对象自身的引用,以便赋值之后的操作   

       你肯定知道这个:   

        int    a,    b;   

        b    =    7;   

        Func(    a    =    b    );    //    把i赋值后传给函数Func(    int    )   

       同理:   

        CMyClass    obj1,    obj2;   

           obj1.Initialize();       

           Func2(    obj1    =    obj2    );    //如果没有返回引用,是不能把值传给Func2的   

        

           注:   

        CMyClass    &    CMyClass::    operator    =    (    CMyClass    &    other    )   

           {   

                   if(    this    ==    &other    )   

                          return    *this;   

                   //    赋值操作...   

                   return    *this   

           }

    ==================================================================================

    赋值运算符和复制构造函数都是用已存在的B对象来创建另一个对象A。不同之处在于:赋值运算符处理两个已有对象,即赋值前B应该是存在的;复制构造函数是生成一个全新的对象,即调用复制构造函数之前A不存在。
      CTemp a(b); //复制构造函数,C++风格的初始化
      CTemp a=b; //仍然是复制构造函数,不过这种风格只是为了与C兼容,与上面的效果一样,在这之前a不存在,或者说还未构造好。
      CTemp a;
      a=b; //赋值运算符
      在这之前a已经通过默认构造函数构造完成。
      实例总结:
      重点:包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符。
      以下讨论中将用到的例子:
      class CExample
      {
      public:
      CExample(){pBuffer=NULL; nSize=0;}
      ~CExample(){delete pBuffer;}
      void Init(int n){ pBuffer=new char[n]; nSize=n;}
      private:
      char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源
      int nSize;
      };
      这个类的主要特点是包含指向其他资源的指针。
      pBuffer指向堆中分配的一段内存空间。
      一、拷贝构造函数
      调用拷贝构造函数1
      int main(int argc, char* argv[])
      {
      CExample theObjone;
      theObjone.Init(40);
      //现在需要另一个对象,需要将他初始化称对象一的状态
      CExample theObjtwo=theObjone;//拷贝构造函数
      ...
      }
      语句"CExample theObjtwo=theObjone;"用theObjone初始化theObjtwo。
      其完成方式是内存拷贝,复制所有成员的值。
      完成后,theObjtwo.pBuffer==theObjone.pBuffer。
      即它们将指向同样的地方(地址空间),指针虽然复制了,但所指向的空间内容并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。
      所以需要采用必要的手段来避免此类情况。
      回顾以下此语句的具体过程:通过拷贝构造函数(系统默认的)创建新对象theObjtwo,并没有调用theObjtwo的构造函数(vs2005试验过)。
      可以在自定义的拷贝构造函数中添加输出的语句测试。
      注意:
      对于含有在自由空间分配的成员时,要使用深度复制,不应使用浅复制。
      调用拷贝构造函数2
      当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调同拷贝构造函数。
      例如
      BOOL testfunc(CExample obj);
      testfunc(theObjone); //对象直接作为参数。
      BOOL testfunc(CExample obj)
      {
      //针对obj的操作实际上是针对复制后的临时拷贝进行的
      }
      调用拷贝构造函数3
      当函数中的局部对象被被返回给函数调者时,也将建立此局部对象的一个临时拷贝,拷贝构造函数也将被调用
      CTest func()
      {
      CTest theTest;
      return theTest
      }
      二、赋值符的重载
      下面的代码与上例相似
      int main(int argc, char* argv[])
      {
      CExample theObjone;
      theObjone.Init(40);
      CExample theObjthree;
      theObjthree.Init(60);
      //现在需要一个对象赋值操作,被赋值对象的原内容被清除,并用右边对象的内容填充。
      theObjthree=theObjone;
      return 0;
      }
      也用到了"="号,但与"一、"中的例子并不同,"一、"的例子中,"="在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号表示。
      例如 CExample theObjone(theObjtwo);
      而本例子中,"="表示赋值操作。将对象theObjone的内容复制到对象theObjthree;,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。
      但"="的缺省操作只是将成员变量的值相应复制。旧的值被自然丢弃。
      由于对象内包含指针,将造成不良后果:为了避免内存泄露,指针成员将释放指针所指向的空间,以便接受新的指针值,这正是由赋值运算符的特征所决定的。但如果是"x=x"即自己给自己赋值,会出现什么情况呢?x将释放分配给自己的内存,然后,从赋值运算符右边指向的内存中复制值时,发现值不见了。
      因此,包含动态分配成员的类除提供拷贝构造函数外,还应该考虑重载"="赋值操作符号。
      类定义变为:
      class CExample
      {
      ...
      CExample(const CExample&); //拷贝构造函数
      CExample& operator = (const CExample&); //赋值符重载
      ...
      };
      //赋值操作符重载
      CExample & CExample::operator = (const CExample& RightSides)
      {
      nSize=RightSides.nSize; //复制常规成员
      char *temp=new char[nSize]; //复制指针指向的内容
      memcpy(temp, RightSides.pBuffer, nSize*sizeof(char));
      delete []pBuffer; //删除原指针指向内容 (将删除操作放在后面,避免X=X特殊情况下,内容的丢失)
      pBuffer=temp; //建立新指向
      return *this
      }
      三、拷贝构造函数使用赋值运算符重载的代码。
      CExample::CExample(const CExample& RightSides)
      {
      pBuffer=NULL;
      *this=RightSides //调用重载后的"="
      }

    展开全文
  • 1.构造函数 1.1 定义 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。 1.2 特性 构造函数是用来...
  • 封装,构造函数,UML

    2021-01-12 22:39:04
    [在这里插入图片描述](https://img-blog.csdnimg.cn/20210112222029645.png)package和import封装特点构造函数构造函数特点构造函数作用创建对象都必须通过构造函数初始化拷贝构造函数一般函数和构造函数什么区别练习...
  • 对 c++类成员函数中的构造函数 拷贝构造函数 析构函数 赋值运算符重载的一些特点以及函数调用顺序,并附上例子,希望对大家有帮助,有错误大家可以指出来。
  • 文章目录构造函数默认构造函数的三种不适用情况第一种第二种第三种 class Date { }; 可以看到,上面那个类没有任何成员,是一个空类,但是它真的什么都没有吗? 其实一个类在我们不写的情况下,也会生成6个默认的...
  • 首先我们先来大致了解类中的6个默认成员函数 当一个类中任何成员都没有的时候,我们就简称其为空类,但是...构造函数:完成初始化工作 析构函数:完成清理工作 拷贝复制 拷贝构造:使用同类对象初始化创建对象 赋...
  • 构造函数是一个特殊的成员函数,名字和类名相同,创建类类型对象时由编译器自动调用,虽然构造函数名称叫做构造,但是它的主要任务是初始化对象,而不是开空间创建对象,在对象的生命周期内只调用一次。如果用户没有...
  • C++ 拷贝构造函数 ...请先记住以下的警告,在阅读正文时就会多心:如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了...
  • java 构造函数浅谈

    2016-12-28 16:31:51
    使用构造器时需要记住: 1.构造器必须与类同名(如果一个源文件中有多个类,那么构造器必须与公共类同名) 2.每个类可以有一个以上的构造器 3.构造器可以有0个、1个或1个以上的参数 4.构造器没有返回值 5.构造...
  • java中的构造函数总结

    2017-03-06 16:03:00
    什么80%的码农都做不了架构师?>>> ...
  • 拷贝构造函数也是特殊的成员函数,其特征如下: 1.拷贝构造函数构造函数的一个重载形式 2.拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。 class Date { public: Date(in...
  •  通常我们都将构造函数的声明置于public区段,假如我们将其放入private区段中会发生什么样的后果?没错,我也知道这将会使构造函数成为私有的,这意味着什么?  我们知道,当我们在程序中声明一个对象时,...
  • 封装过程中的疑难杂症(二,构造函数以及类的应用) 一,构造函数 1,定义 (1),C#构造函数是在创建给定类型的对象时执行的类方法。 (2),构造函数没有返回值(void也不需要) (3),如果一个类中可以有多个构造函数 ,可根据其...
  • 1.类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。...2. 构造函数 2.1 概念 对于以下的日期类: class Date{ public: void SetDate(int year,int month,int day ){ _year=year; _mon...
  • 构造函数 析构函数 拷贝构造函数 赋值运算符重载函数 取地址操作符重载 const 修饰的取地址操作符重载 今天我们将着重讲述前三个。 不少难以察觉的程序错误是由于变量没有被正确初始化或清除造成的,而初始化和清除...
  • 一、首先我们必须知道什么时候要重写拷贝构造函数和赋值函数 如果类的对象中包含指针,指向动态分配的内存资源,一般都要重写拷贝构造函数和赋值函数 例如下面的类: class Example { public:  Example(){...
  • 一、构造函数 1、概念  构造函数是一种特殊的成员函数。名字与类名相同,创建类类型对象时,由编译器自动调用,在对象的声明周期内只调用一次,以保证每个数据成员都有一个合适的初始值。   2、构造函数的特性...
  • 构造函数与普通函数的区别

    千次阅读 2017-04-18 19:01:06
    本篇博文主要是为新手、对java语言感兴趣的人和那些没有系统学习过java基础知识的人进行一个总结,在文章中对构造函数进行了较为详细的说明和讨论,也包含了我个人对于java面向对象中构造函数的一些看法。...
  • 在C++中,类的默认构造函数有六个,他们分别是构造函数,拷贝构造函数,析构函数,赋值操作符重载,取地址操作符重载和const修饰的取地址操作符重载。今天对其中的构造函数,拷贝构造函数,析构函数,赋值操作符重载...
  • 构造函数、原型和原型链构造函数构造函数简介静态成员和实例成员构造函数和类的区别构造函数的问题原型构造函数原型 prototype__proto__对象原型constructor 构造函数构造函数、实例、原型对象三者之间的关系原型链 ...
  • 文章目录类的6个默认成员函数构造函数特性要点总结: 类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。空类中什么都没有吗?并不是的,任何一个类在我们不写的情况下,都会自动生成下面6个默认成员...
  • 类的成员函数1 类的构造函数1.1 构造函数的概念1.2 构造函数的特性2 类的析构函数2.1 析构函数概念2.2 析构函数的特性3 类的拷贝/复制构造函数3.1 拷贝/复制构造函数的概念3.2 拷贝/复制构造函数特征4 类的赋值...
  • d的复制构造函数

    2020-02-15 13:53:49
    本节重点介绍了后复制存在问题,并说明了为什么复制构造函数比后复制好. 本(本)概述 无法有意义地重载或限定后复制函数.但,编译器不会拒绝限定器应用,如下所示: 构 A{本(本)常 {}} 构 B{本(本)不变{}} 构 C{本(...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 74,938
精华内容 29,975
关键字:

以下什么不是构造函数的特征