我们正在更新 Microsoft Text Input Application,应该很快就可以再次使用了?

mit调用,给这个方法添加一个参数,就是mutation的载荷(payload

2.route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

State就是数据源的存放地

State里面的数据是响应式的,state中的数据改变,对应这个数据的组件也会发生改变

Getter可以对state进行计算操作,它就是store的计算属性

Getter可以在多组件之间复用

如果一个状态只在一个组件内使用,可以不用getters

更改vuex  store中修改状态的唯一办法就是提交mutation,可以在回调函数中修改store中的状态

Action类似于mutation,不同的是 action提交的是mutation,不是直接变更状态,可以包含任意异步操作

优点:解决了非父子组件的通信,减少了ajax请求次数,有些可以直接从state中获取

缺点:刷新浏览器,vuex中的state会重新变为初始状态,解决办法是vuex-along,得配合计算属性和sessionstorage来实现

55.Vue路由懒加载(按需加载路由)

首先不要把v-if与v-for用在同一个元素上,原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。

传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。JQuery ajax 是对原生XHR的封装

axios 是一个基于Promise ,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,

方式1:通过bind方法进行原地绑定,从而改变this指向

方式2:通过创建箭头函数

方式3:在constructor中提前对事件进行绑定

方式4:将事件调用的写法改为箭头函数的形式

请简述你对react的理解

声明式设计:react采用范式声明,开发者只需要声明显示内容,react就会自动完成

高效: react通过对dom的模拟(也就是虚拟dom),最大限度的减少与dom的交互

灵活: react可以和已知的库或者框架很好配合

组件: 通过react构建组件,让代码更容易复用,能够很好应用在大型项目开发中,把页面功能拆分成小模块  每个小模块就是组件

单向数据流:  react是单向数据流,数据通过props从父节点传递到子节点,如果父级的某个props改变了,react会重新渲染所有的子节点

react组件之间的数据传递

逆向传值用函数传值 通过事件调用函数传递

  1. 都有虚拟dom,组件化开发,通过props参数进行父子组件数据的传递,都实现webcomponent规范
  1. 虚拟dom不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个dom组件树,而react不同,当应用的状态被改变时,全部组件都会重新渲染,所以react中用shouldcomponentupdate这个生命周期的钩子函数来控制
  2. 数据绑定不一样,vue实现了数据双向绑定,react数据流动是单向的
  3. 在react中,state对象需要用setstate方法更新状态,在vue中,state对象不是必须的,数据由data属性在vue对象中管理

请简述虚拟dom与diff算法

虚拟DOM也就是常说的虚拟节点,它是通过js的object对象模拟DOM中的节点,然后再通过特定的渲染方法将其渲染成真实的DOM节点。

频繁的操作DOM,或大量造成页面的重绘和回流

Diff算法:把树形结构按照层级分解,只比较同级元素,给列表结构的每个单元添加唯一的key值,方便比较

可组合,可复用,可维护,可测试

React在调用setstate后,react会将传入的参数对象和组件当前的状态合并,触发调和过程,

在调和过程中,react会根据新的状态构建react元素树重新渲染整个UI界面,在得到元素树之后,react会自动计算新老节点的差异,根据差异对界面进行最小化重新渲染

虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能

Props是一个从外部传进组件的参数,主要作用就是父组件向子组件传递数据,但是props对于使用它的组件来说是只读的,一旦赋值不能修改,只能通过外部组件主动传入新的props来重新渲染子组件

一个组件的显示形态可以由数据状态和外部参数决定,外部参数是props,数据状态就是state,首先,在组件初始化的时候,用this.state给组件设定一个初始的state,在第一次渲染的时候就会用这个数据来渲染组件,state不同于props一点时,state可以修改,通过this.setState()方法来修改state

这个react生命周期钩子函数是来解决这个问题:

在更新数据的时候用setState修改整个数据,数据变了之后,遍历的时候所有内容都要被重新渲染,数据量少还好,数据量大就会严重影响性能

  1. component diff 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件会生成不同的树形结构
  2. element diff 对于同一层级的一组子节点,他们可以通过唯一的id进行区分

React负责渲染表单的组件,值是来自于state控制的,输入表单元素称为受控组件

Super()调用父类的构造方法,有super,组件才有自己的this,在组件全局中都可以使用this,如果只是constructor而不执行super,之后的this都是错的,super继承父组件的this

React 中构建组件的方式

自定义组件:函数组件或者无状态组件  组件首字母大写

类组件:一个类组件必须实现一个render方法,这个方法必须返回一个jsx元素,要用一个外层的元素把所有内容包裹起来

无需下载安装,直接使用,运行速度快,项目搭建迅速,短小精悍,每个app源代码不超过2mb

小程序的页面构成(4个文件)

如何提高小程序的首屏加载时间

提前请求:异步数据数据请求不需要等待页面渲染完成

利用缓存:利用storage API对异步请求数据进行缓存,二次启动时先利用缓存数据渲染页面,再进行后台更新

避免白屏:先展示页面骨架和基础内容

及时反馈:及时地对需要用户等待的交互操作给出反馈,避免用户以为小程序没有响应

请简述你经常使用的小程序的组件

提供了全局样式和局部样式

减少默认data的大小

小程序如何显示用户头像与用户名

传统接口wx.getuserinfo 目前可以用,需要用户授权,使用时会有官方发提示,这个方法需要升级

最新方法:open-data标签,使用这个标签可以不用用户授权直接获取头像和用户名,

可以在button中将opendata作为属性写进去,写个点击事件就直接获取到了

请谈谈小程序的双向绑定和vue的异同?

Vue双向绑定是通过数据拦截和观察者模式,通过this.value获取值,小程序是通过触发表单元素绑定的方法,在方法中用this.setData({key:value})来取值

小程序中传参是怎么传的

说一下微信小程序的适配问题

小程序页面间有哪些传递数据的方法?

你是怎么封装微信小程序的数据请求的

说一下微信小程序的适配问题

微信小程序如何跳转到其他小程序

小程序加载过慢的解决方式

Gulp是一种能够优化前端开发流程的工具,webpack是一种模块化的解决方案 (grunt)

什么是loaders,loaders是文件加载器,能够加载资源文件,并对这些文件进行处理,例如,编译,压缩等,最终一起打包到指定文件中。

什么是plugin,在webpack运行的生命周期会有许多事件,plugin可以监听这些事件

怎么提升页面性能?性能优化有哪些?

Node使用来做什么的

Webpack:入口,出口,加载器,插件

说一下webpack的打包原理

Webpack是把项目当做一个整体,通过给定一个主文件,webpack将从这个主文件开始找到项目中所有依赖的文件,使用loaders类处理,最后打包成一个或者多个浏览器可识别的js文件

  1. common模块是拷贝,可以修改值,es6模块是引用,只读状态,不能修改值
  2. commonjs模块是运行时加载,es6模块是编译时输出接口

Git如何使用/常用指令有哪些

你们后台用的是什么技术

你的项目比较小为什么还是用vue全家桶

请简述你在项目中使用的ui框架

前端性能优化的方式越多越好

Websocked是一种双向通信协议,在建立连接后,websocked服务器和浏览器都能主动向对方发送或者接收数据,websocked需要类似于tcp的客户端和服务器通过握手连接,连接成功后才能互相通信

后台传递过来的数据是那些

1.WEB前端项目开发流程

这个环节是由项目经理完成,项目经理首先和客户进行交流,了解客户的需求,然后分析项目的可行性,如果项目可以被实现,项目经理写出项目需求文档交给设计师完成后续的开发。

这个环节主要是UI设计师参与,UI设计师根据产品需求分析文档,对产品的整体美术风格、交互设计、界面结构、操作流程等做出设计。负责项目中各种交互界面、图标、LOGO、按钮等相关元素的设计与制作。并且确定使用技术

这个部分由程序员来实现。(程序员分为WEB前端开发工程师和后台开发工程师。前端开发人员主要做我们可以在网页上看的见的页面,后台就做一些我们看不见的管理系统以及功能的实现。)程序员根据UI设计师的设计,用编码来完成整个项目的各个功能。

这部分由程序测试员来完成。程序测试员主要就是测试寻找程序还存在的bug,一般来说刚编码完成的程序都是存在问题的,就需要测试人员反复不断的测试并将存在问题的测试结果交给编码人员进行bug的修复。等到几乎所有bug修复完成,这个项目差不多就可以上线了。

程序的维护是整个项目的最后一个阶段,但也是耗时最多,成本最高最高的的一个阶段。程序的维护包括程序上线后后续bug的修复和程序版本的更新。

就是在开发的时候调用的后台接口是后台测试的接口  项目上线后要把请求的接口替换成上线的域名

代码管理平台:github 码云

需求发布平台:钉钉任务,禅道

产品原型工具:axure

企业邮箱:阿里 腾讯企业邮箱

4大公司和小公司开发的区别

大型外包公司更加流程化,人员多,沟通少,项目交付后不需要自己维护,采用瀑布开发模式(以文档为主)

小型公司:人少 需求经常改变 沟通方便 采用敏捷开发(快速推出v1版本 ,之后迭代)

5.前后台分离怎么测试?

你们后端开发用的什么?

项目中自己觉得骄傲的地方?

怎么调用接口(是怎么跟后台沟通的)

开发环境,测试环境,上线环境的环境变量你们在开发中是如何处理的

C++ 中的变量类型与Java很相似。像Java一样,C++ 有int 和 double 类型。但是这些数字类型的取值范围是依赖于机器的。比如在16位系统上,例如运行DOS 或Windows 3.x的PC机上,int 是双字节(2-byte)的,取值范围比Java的4-byte的int 要小很多。在这些机器上,如果 int 不够用的话,你需要使用长整型long。

C++ 有 short 和 unsigned 类型来更有效的存储数字。(我认为所谓有效是指更高的空间利用率。) 最好是尽量避免使用这些类型除非是空间利用的有效性对你的系统真的非常重要。

C++ 中字符串类型用 string 表示。它与Java中的 String 类型非常相似,但是,还是要逐一以下几点不同之处:

2. C++ 字符串是可以被修改的,而Java字符串的内容是不可修改的(immutable)。

3. 取子字符串的操作在 C++ 中叫做 substr,这个命令s.substr(i, n) 从字符串s中取得从位置 i 开始长度为n的子字符串。

4. 在C++中,你只能够将字符串与其它字符串对象相串联(concatenate),而不能够与任意的对象相串联。

5. C++中可以直接使用关系操作符 ==、 !=、 <、 <=、 >、 >= 来进行字符串比较,其中后面四个操作符是按字母顺序进行比较的。 这比Java中使用函数equals和compareTo来比较要方便很多。

在C++中,本地变量的定义看起来与Java中相同,例如:

实际上这正是C++和Java的一个重要不同之处。C++编译器不对本地变量进行初始化检验,所以在C++中很容易忘记初始化一个变量,这种情况下,变量的值该变量所占内存区域中刚好当前存在随机值。这显然是很容易产生程序出错的地方。

与Java一样, C++中类可以有数据域和静态变量。不同的是,C++中变量可以在函数甚至是类的外面定义,这些所谓的全局变量可以在程序的任何函数中被访问,因而不易被很好的管理。所C++中应该尽量避免使用全局变量。

在C++中,常量可以在任何地方被定义(记得在Java中,常量必须是类的静态数据static data)。 C++ 使用关键字 const 来定义常量,而Java中是 final。例如:

C++ 中对类的定义与Java有些不同,这里是一个例子:一个C++ 版本的 Point 类:

这里几点重要的不同是:

2. C++中类的定义只包含函数的声明,真正的实现另外单独列出。

4. 类定义的结尾处有分号

类中函数的实现跟在类的定义之后。因为函数是在类外面定义的,所以每一个函数的名字前面要加类名称作为前缀,并使用操作符双冒号::来分割类的名称和函数的名称。不改变隐含参数值(即当前对象的值)的访问函数用 const标明。如下所示是上面类定义中的函数的实现:

Java 与 C++ 最主要的不同在于对象变量的使用。在 C++中,对象变量存储的是真正的对象的值,而不是对象引用(reference)。注意在C++中构造一个对象的时候是不使用关键字new的,只需要在变量的名字后面直接赋予构造函数的参数就可以了,例如:

如果不跟参数赋值,则使用默认构造函数,例如:

这一点与Java很不同。在Java中,这个命令仅仅生成一个没有初始化的reference,而在C++中,它生成一个实际的对象。

当一个对象被赋给另一个对象变量的时候,实际的值将被拷贝。而在Java中,拷贝一个对象变量只不过是建立了另外一个指向对象的reference。拷贝一个C++的对象就像在Java中调用clone这个函数一样,而修改拷贝的值不会改变原对象的值。例如:

多数情况下,C++中这种对象直接对值操作的特性使用起来很方便,但是也有些时候不尽如人意:

1. 当需要一个函数中修改一个对象的值,必须记住要使用按引用调用call by reference (参见下面函数部分)

2. 两个对象变量不能指向同一个对象实体。如果你要在C++中实现这种效果,必须使用指针pointer(参见下面指针部分)

3. 一个对象变量只能存储一种特定的类型的值,如果你想要使用一个变量来存储不同子类的对象的值(多态ploymorphism),则需要使用指针。

4. 如果你想在C++中使用一个变量来或者指向null或者指向一个实际的对象,则需要使用指针

在Java中,每一个函数必须或者是对象函数(instance method),或者是静态函数(static function)或称类函数。C++同样支持对象函数和静态函数(类函数),但同时C++也允许定义不属于任何类的函数,这些函数叫做全局函数(global functions)。

特别的是,每一个C++ 程序都从一个叫做 main的全局函数开始执行:

还有另外一个格式的main函数可以用来捕捉命令行参数,类似于Java的main函数,但是它要求关于C格式的数组和字符串的知识,这里就不介绍了。

按照习惯,通常如果程序执行成功, main 函数返回0,否则返回非零整数。

同Java一样,函数参数是通过值传递的(passed by value)。在Java中,函数无论如何都是可以修改对象的值的。然而在C++中,因为对象直接存储的是实际的值,而不是指向值的reference,也就是说传入函数的是一个实际值的拷贝,因此也就无法修改原来对象的值。

所以,C++ 有两种参数传递机制,同Java一样的按值调用(call by value) ,以及按地址调用(call by reference)。当一个参数是按reference传递时,函数可以修改其原始值。Call by reference 的参数前面有一个地址号 & 跟在参数类型的后面,例如:

下面是一个典型的利用call by reference的函数,在Java中是无法实现这样的功能的。

如果使用 swap(x, y)来调用这个函数,则reference参数 a 和 b 指向原实际参数x 和 y的位置,而不是它们的值的拷贝,因此这个函数可以实现实际交换这两个参数的值。

在 C++中,每当需要实现修改原参数的值时你就可以使用按地址调用 call by reference

C++ 的向量结构结合了Java中数组和向量两者的优点。一个C++ 的向量可以方便的被访问,其容量又可以动态的增长。如果 T 是任意类型,则 vector<T> 是一个元素为 T 类型的动态数组。下面的语句

产生一个初始为空的向量。而语句

生成一个初始有100个元素的向量。你可以使用push_back 函数来添加元素:

调用 a.pop_back() 从a中取出最后一个元素(操作后这个元素被从a中删掉), 使用函数size 可以得到当前a中的元素个数。

你还可以通过我们熟悉的 [] 操作符来访问向量中元素,例如:

同Java中一样,数组索引必须为 0 和 a.size() - 1之间的值。但是与Java不同的是,C++中没有runtime的索引号合法性检验。试图访问非法的索引位置可能造成非常严重的出错。

就像所有其它 C++ 对象一样,向量也是值。如果你将一个向量赋值给另外一个向量变量,所有的元素都会被拷贝过去。

对比Java中的情况,在Java中,一个数组变量是一个指向数组的reference。拷贝这个变量仅仅产生另外一个指向同一数组的reference,而不会拷贝每一个元素的值。

正因如此,如果一个C++函数要实现修改向量的值,必须使用reference参数:

在C++中,标准的输入输出流用对象 cin 和 cout 表示。我们使用 << 操作符写输出,例如:

也可以连着输出多项内容,例如:

我们使用 >> 操作符来读入一个数字或单词,例如:

函数getline 可以读入整行的输入,例如:

如果到达输入的结尾,或者一个数字无法被正确的读入,这个流对象会被设置为 failed 状态,我们可以使用函数 fail 来检验这个状态,例如:

一旦一个流的状态被设为failed,我们是很难重置它的状态的,所以如果你的程序需要处理错误输入的情况,应该使用函数 getline 然后人工处理得到的输入数据。

我们已经知道在C++中,对象变量直接存储的是对象的值。这是与Java不同的,在Java中对象变量存储的是一个地址,该地址指向对象值实际存储的地方。有时在C++中也需要实现这样的布置,这就用到了指针pointer。在 C++中,一个指向对象的变量叫做指针。如果T是一种数据类型,则 T* 是指向这种数据类型的指针。

就像 Java中一样,一个指针变量可以被初始化为空值 NULL,另外一个指针变量的值,或者一个调用new生成的新对象:

实际上在C++中还有第四种可能,那就是指针可以被初始化为另外一个对象的地址,这需要使用地址操作符 & :

这实际上并不是什么好主意。保险的做法还是应该直接让指针指向使用 new生成的新对象。

到目前为止,C++ 指针看起来非常像 Java 的对象变量。然而,这里有一个很重要的语法的不同。我们必须使用星号操作符 * 来访问指针指向的对象。如果 p 是一个指向Employee对象的指针,则 *p 才代表了这个对象:

当我们需要执行对象的函数或访问对象的一个数据域时,也需要使用 *p :

*p外面的括号是必需的,因为 . 操作符比 * 操作符有更高的优先级。C的设计者觉得这种写法很难看,所以他们提供了另外一种替代的写法,使用 -> 操作符来实现 * 和 . 操作符的组合功能。表达式

可以调用对象*p的函数 setSalary 。你可以简单的记住 . 操作符是在对象上使用的,-> 操作符是在指针上使用的。

如果你不初始化一个指针,或者如果一个指针为空值 NULL 或指向的对象不再存在,则在它上面使用 * 或 -> 操作符就会出错。 不幸的是 C++ runtime 系统并不检查这个出错。如果你范了这个错误,你的程序可能会行为古怪或死机。

而在Java中,这些错误是不会发生的。所有的reference都必须初始化,所有的对象只要仍有reference指向它就不会被从内存中清除,因此你也不会有一个指向已被删除的对象的reference。Java的runtime 系统会检查reference是否为空,并在遇到空指针时抛出一个null pointer的例外(exception)。

C++ 和 Java还有一个显著的不同,就是 Java 有垃圾回收功能,能够自动回收被废弃的对象。而在C++中,需要程序员自己管理内存分配回收。

C++中当对象变量超出范围时可以自动被回收。但是使用new生成的对象必须用delete操作符手动删除,例如:

如果你忘记删除一个对象,那么你的程序有可能最终用光所有内存。这就是我们常说的内存泄漏 (memory leak)。更重要的是,如果你如果删除了一个对象,然后又继续使用它,你可能覆盖不属于你的数据。如果你刚巧覆盖了用于处理内存回收的数据域,那么内存分配机制就可能运转失常而造成更严重的错误,而且很难诊断和修复。因此,在C++中最好尽量少用指针

C++和Java中继承的基本语法是很相似的。在C++中,使用 : public 代替Java中的extends 来表示继承关系 。 (C++ 也支持私有继承的概念,但是不太有用。)

默认情况下,C++中的函数不是动态绑定的。如果你需要某个函数实现动态绑定,需要使用virtual声明它为虚函数,例如:

同Java一样,构造函数中调用父类的构造函数有特殊的语法。 Java使用关键字 super。C++中必须在子类的构造函数体外调用父类的构造函数。下面是一个例子:

Java 中在子类函数中调用父类的函数时也使用关键字 super 。而在C++中是使用父类的名称加上操作符 ::表示,例如:

一个 C++ 对象变量只能存储特定类型的对象值。要想在C++中实现多态(polymorphism),必须使用指针。一个 T* 指针可以指向类型为 T 或 T 的任意子类的对象,例如:

你可以将父类和不同子类的对象混合收集到一个元素均为指针的向量中,然后调用动态绑定的函数,如下所示:

使用这个函数, 表达式 ++x 才有正确的显示以及正确的操作。

C++在这里并没有给我们选择的余地。
每个重载的操作符函数必须或者是一个类的成员, 或者使用类型T、 T & 或 T const & 为参数类型,

也就是说,每一个重载操作符必须以类或列举类型为参数类型。

指针,即使是指向一个类或列举类型对象的指针,也不可以用。

C++ 不允许在重载操作符时重新定义内置操作符的含义,包括指针类型。
因此,我们不可以定义:
因为它试图对int重新定义操作符 ++ 的含义。 我们也不可以定义:
因为它试图对 int * 重新定义操作符 ++ 的含义

一个pointer在它的有生之年可以指向许多不同的对象,
而一个reference只能够指向一个对象。
在强调一遍,一旦一个reference与一个对象绑定,就不能再将它改指向另外的东西。
既然不能再绑定reference之后再 改变, 一个reference就必须在一出生就被绑定。
否则这个reference就永远不能被绑定到任何东西,也就毫无用处了。

上一段的讨论也同样完全适用于常量指针(const pointer)。
一个reference声明必须同时带有一个初始化赋值,如下所示:

一个常量指针的声明也同样必须带有一个初始化赋值,如下所示:

除了显示的不同,常量指针与reference还有一点非常不同,那就是,一个有效的reference必须指向一个对象;而一个指针不需要。一个指针,即使是一个常量指针, 都可以有空值。 一个空指针不指向任何东西。

这点不同就暗示当你想要确信一个参数必须指向一个对象的时候,应该使用reference作为参数类型。 例如,交换函数(swap function),它接受两个int参数,并将两个参数的数值对调,如下所示:

将原本在 i 中的值放到 j 中, 并将原本在 j 中的值放到 i 中。我们可以这样写这个函数:

这个接口暗示其中一个或两个参数都有可能为空(null)。而这个暗示是误导的。例如,调用
的后果很可能是不愉快的。

而像下面这样定义reference为参数:

常量指针与reference还有一点非常不同,
那就是,一个有效的reference必须指向一个对象;

一个指针,即使是一个常量指针, 都可以有空值。 一个空指针不指向任何东西。

这点不同就暗示当你想要确信一个参数必须指向一个对象的时候,应该使用reference作为参数类型。
交换函数(swap function),它接受两个int参数,并将两个参数的数值对调,如下所示:

将原本在 i 中的值放到 j 中, 并将原本在 j 中的值放到 i 中。我们可以这样写这个函数:

这个接口暗示其中一个或两个参数都有可能为空(null)。而这个暗示是误导的。例如,调用
的后果很可能是不愉快的。

而像下面这样定义reference为参数:

有些人认为既然reference不能够为空,那么它应该比指针更安全。
我认为reference可能要安全一点,但不会安全很多。
虽然一个有效的reference不能为空,但是无效的可以呀。
实际上,在很多情况下程序有可 能产生无效的reference,而不只是空的reference。

你可以定义一个reference,使它绑定到一个指针指向的对象,如下所示:

从技术上来说,这个错误并不在于将reference绑定到一个空值,而是在于对一个空指针去参考。
对一个空指针去参考产生了一个不确定的操作,也就意味着很多事都可能发生,而且大部分都不是什么好事。很有可能当程序将reference r 绑定到*p (p所指向的对象)的时候,p实际上没有被去参考,甚至程序只是将p的值拷贝给实现r的指针。
而程序将会继续执行下去直到错误在后面的运行中更为明显的表 现出来,产生不可预知的危害。

另外一种产生无效reference的方法:

这个函数返回一个指向本地变量 i 的reference。
然而当函数返回时,本地变量 i 的存储空间也就消失了。因此这个函数实际返回了一个指向被回收了的空间的reference。这个操作与返回一个指向本地变量的指针的后果相同。
有些编译 器可以在编译时发现这个错误,但也很有可能不会发现。

我喜欢reference,也有很好的理由使用它们代替pointer。

但如果你期望使用reference来使你的程序健壮性显著增强,那么你多半会失望的

VC6.0中重载操作符函数无法访问类的私有成员
在 C++ 中,操作符(运算符)可以被重载以改写其实际操作。
同时我们可以定义一个函数为类的朋友函数(friend function)以便使得这个函数能够访问类的私有成员,
这个定义通常在头文件中完成。

在Visual C++中定义一般的函数为朋友函数通常是没有问题的。
然而对某些重载操作符的函数,
即使我们将它们定义为类的朋友函数,VC的编译器仍然会显示出错信息,
认为这些朋友函数无权访问类的私有成员。
我认为这应该是VC6.0的bug。

以上代码在gnuc++中编译运行毫无问题。但是在VC++6.0中编译的时候就会出现以下的编译错误:

在VC++ 6.0中解决这个问题有以下几种方法:

这个操作符可以在互不相关的类之间进行指针转换,
操作的结果是简单的将一个指针的二进制数据(binary copy)复制到另一个指针。
对指针指向的内容不做任何检查或转换。

static_cast 可以执行所有能够隐含执行的类型转换,以及它们的反向操作(即使这种方向操作是不允许隐含执行的)。

用于类的指针,也就是说,它允许将一个引申类的指针转换为其基类类型(这是可以被隐含执行的有效转换),同时也允许进行相反的转换:将一个基类转换为一个引申类类型。

在后面一种情况中,不会检查被转换的基类是否真正完全是目标类型的。例如下面的代码是合法的:

译者注:如果你对这部分看不太懂,请结合下面的dynamic_cast一起看,也许会帮助理解。

dynamic_cast 完全被用来进行指针的操作。它可以用来进行任何可以隐含进行的转换操作以及它们被用于多态类情况下的方向操作。

dynamic_cast 会检查后一种情况的操作是否合法,
也就是说它会检查类型转换操作是否会返回一个被要求类型的有效的完整的对象。

这种检查是在程序运行过程中进行的。如果被转换的指针所指向的对象不是一个被要求类型的有效完整的对象,返回值将会是一个空指针NULL 。

如果类型转换被用在引用(reference)类型上,而这个转换不可能进行的话,一个bad_cast 类型的例外(exception)将会被抛出:

这种类型转换对常量const 进行设置或取消操作:

它检查一个表达式的类型:

这个操作符返回一个类型为type_info的常量对象指针,这种类型定义在标准头函数中。这种返回值可以用操作符 == 和 != 来互相进行比较,
也可以用来通过name()函数获得一个描述数据类型或类名称的字符串,

我们能够找到的关于名空间的最好的例子就是标准C++ 函数库本身。

标准C++库中的所有类、对象和函数都是定义在名空间std下面的。

你可能已经注意到,我们在这个教程中全部忽略了这一点。作者决定这么做是因为这条规则几乎和ANSI 标准本身一样年轻 (1997) ,许多老一点的编译器并不兼容这条规则。

几乎所有的编译器,即使是那些与ANSI 标准兼容的编译器,都允许使用传统的头文件 (如iostream.h, stdlib.h, 等等),就像我们在这个教程中所使用的一样。

然而,ANSI标准完全重新设计了这些函数库,
而且遵循了这条规则将所有的函数和变量定义在了名空间std下。

该标准为这些头文件定义了新的名字,对针对C++的文件基本上是使用同样的名字,但没有.h的扩展名,

如果我们使用ANSI-C++ 兼容的包含文件,我们必须记住所有的函数、类和对象是定义在名空间 std 下面的,例如:

更常用的方法是使用using namespace ,这样我们就不必在所有标准空间中定义的函数或对象前面总是使用范围操作符::了 :

对于STL 用户,强烈建议使用ANSI-compliant 方式来包含标准函数库。

从编译器的角度来看,模板不同于一般的函数或类。
也就是说一个模板的代码直到需要生成一个对象的时候(instantiation)才被编译。
当需要instantiation的时候,编译器根据模板为特定的调用数据类型生成一个特殊的函数。

当工程变得越来越大的时候,程序代码通常会被分割为多个源程序文件。

模板这种类似宏(macro-like) 的功能,对多文件工程有一定的限制:
函数或类模板的实现 (定义) 必须与原型声明在同一个文件中。
也就是说我们不能再 将接口(interface)存储在单独的头文件中,
而必须将接口和实现放在使用模板的同一个文件中。

回到函数库的例子,如果我们想要建立一个函数模板的库,我们不能再使用头文件(.h) ,取而代之,我们应该生成一个模板文件(template file),将函数模板的接口和实现 都放在这个文件中 (这种文件没有惯用扩展名,除了不要使用.h扩展名或不要不加任何扩展名)。

在一个工程中多次包含同时具有声明和实现的模板文件并不会产生链接错误 (linkage errors),因为它们只有在需要时才被编译,而兼容模板的编译器应该已经考虑到这种情况,不会生成重复的代码。

C++ 标准,为了避免它们被多次重复声明,
而不能够包括其定义(初始化操作)。
为了初始化一个静态数据成员,
我们必须在class之外(在全域范围内),
包括一个正式的定义,就像上面例子中做法一样。

在提醒一次,它其实是一个全域变量。唯一的不同是它的名字跟在class的后面。

就像我们会在class中包含static数据一样,我们也可以使它包含static 函数。
它们表示相同的含义:static函数是全域函数(global functions),但是像一个指定class的对象成员一样被调用。
它们也不能够使用关键字this,因为this实际引用了一个对象指针,
但这些 static函数却不是任何object的成员,而是class的直接成员。

定义一个class而没有明确定义构造函数的时候,编译器会自动假设两个重载的构造函数
实际上,当我们定义一个class而没有明确定义构造函数的时候,

例如,对以下class:

编译器自动假设它有以下constructor 成员函数:

它是一个没有任何参数的构造函数,被定义为nop (没有语句)。它什么都不做。

它是一个只有一个参数的构造函数,该参数是这个class的一个对象,这个函数的功能是将被传入的对象(object)的所有非静态(non-static)成员变量的值都复制给自身这个object。

只有在没有其它构造函数被明确定义的情况下才存在。

如果任何其它有任意参数的构造函数被定义了,这两个构造函数就都不存在了。

就必需要自己定义它们。

研究几个C/C++编译器
今天在这里看一个程序,做了一点修改,拿Dev-C++编译了一下,运行通过,只是有几个Warning。文章作者说他是用LCC-Win32编译的,上网查了一下,LCC-Win32现在已经收费了,只在天空下载到一个LCC-Win32 V3.0。LCC-Win32是个C语言编译器,编译出来的程序只有14K,比起Dev-C++的460K来真是小太多了。一直很疑惑Dev-C++编译出来的可执行文件怎么那么大,难道GCC在Windows下只能编译得那么大?还是我没有配置好?

在网上搜了一下其他Windows下的C++编译器,看到这篇《微软的免费 C++ 编译器》,提到了微软的Visual C++ Toolkit 2003。这套软件是免费的,但是小气的微软已经不再提供下载了。上网搜了一下,找到了微软网站的VCToolkitSetup.exe文件下载链接,当然这个链接已经不能用了,我直接扔到迅雷里下载,迅雷帮忙找到了两个下载地址:地址一,地址二。下载下来查看了一下MD5,90D8B963CA196AAC3174C14,没问题。

文章中说这个VC 7.1可以用来编译python和Firefox,不过我安装的时候安装程序自动重启了我的系统,555,今天不研究了,逃。

Update:好像C++程序开头加了#include <iostream>的话,生成的exe文件大小就会从20k左右上升到三、四百k。iostream不能不用啊,伤脑筋啊。另外,把编译器选项里的连接器->剥除附加信息设成yes,可以有效的缩小编译的程序的大小,大概可以从400多k缩小的200多k。

我要回帖

更多关于 苹果8用系统更新后用电很快 的文章

 

随机推荐