Add files via upload
积累Java与C++后端开发比较的知识点,便于多途径找岗位
This commit is contained in:
parent
c2f5d89942
commit
ad575d73d9
80
notes/Java与C++后端开发.md
Normal file
80
notes/Java与C++后端开发.md
Normal file
@ -0,0 +1,80 @@
|
||||
# 关键字
|
||||
|
||||
| 关键字 | Java | C++ |
|
||||
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| **volatile** | 它表示**可见性**。即被该关键字修改的变量的读操作一定在该变量的写更新后。 | (1)**易变性**--在汇编层面来看,即读取该变量的值时直接从内存中读取,而不是从寄存器。<br />(2)"**不可优化**"特性。<br />(3)"**顺序性**"--保证volatile变量间的顺序性,编译器不会进行乱序优化。 |
|
||||
| **static** | (1)修饰类中成员变量。<br />(2)修饰类中方法。表示该方法属于整个类而不属于类的特定实例<br />(3)修饰代码块。 | 控制变更的**存储方式和可见性**<br />(1)修饰局部变量——原本局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了。但是如果**用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束**。但是在这里要注意的是,虽然用static对局部变量进行修饰过后,其生命周期以及存储空间发生了变化,但是其作用域并没有改变,其仍然是一个局部变量,作用域仅限于该语句块。<br />(2)修饰全局变量——原本对于一个全局变量,它既可以在本源文件中被访问到,也可以在同一个工程的其它源文件中被访问(只需用extern进行声明即可)。用static对全局变量进行修饰**改变了其作用域的范围,由原来的整个工程可见变为本源文件可见**。<br />(3)修饰函数。——与修饰全局变量大同小异,就是改变了函数的作用域。<br />(4)C++中的static(中的某个函数用static进行修饰,则表示该函数属于一个类而不是属于此类的任何特定对象;如果对类中的某个变量进行static修饰,表示该变量为类以及其所有的对象所有。它们在存储空间中都只存在一个副本。可以通过类和对象去调用。 ) |
|
||||
| **const**(常量限定符) | (1)修饰**类**。——表明该类不能被继承<br />(2)修饰对象。——表明该对象引用不可修改,当然对象的值依然可被修改<br />(3) | const名叫常量限定符,用来限定特定变量,以通知编译器该变量是不可修改的。习惯性的使用const,可以避免在函数中对某些不应修改的变量造成可能的改动。<br/> <br/>(1)const修饰基本数据类型<br/><br/> 1.const修饰一般常量及数组<br/> <br/> 基本数据类型,修饰符const可以用在类型说明符前,也可以用在类型说明符后,其结果是一样的。在使用这些常量的时候,只要不改变这些常量的值便好。 <br/> <br/> 2.const修饰指针变量*及引用变量& <br/> <br/>如果const位于星号*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;<br/><br/>如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。<br/><br/>(2)const应用到函数中, <br/><br/> 1.作为参数的const修饰符<br/> <br/> 调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,保护了原对象的属性。<br/> [注意]:参数const通常用于参数为指针或引用的情况; <br/> <br/> 2.作为函数返回值的const修饰符<br/> <br/> 声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。<br/><br/>(3)const在类中的用法<br/><br/>不能在类声明中初始化const数据成员。正确的使用const实现方法为:const数据成员的初始化只能在类构造函数的初始化表中进行<br/>类中的成员函数:A fun4()const; 其意义上是不能修改所在类的的任何变量。<br/><br/>(4)const修饰类对象,定义常量对象 <br/>常量对象只能调用常量函数,别的成员函数都不能调用。<br/><br/>http://www.cnblogs.com/wintergrass/archive/2011/04/15/2015020.html |
|
||||
| **extern** | —— | 在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。<br/><br/>注意extern声明的位置对其作用域也有关系,如果是在main函数中进行声明的,则只能在main函数中调用,在其它函数中不能调用。其实要调用其它文件中的函数和变量,只需把该文件用#include包含进来即可,为啥要用extern?因为用extern会加速程序的编译过程,这样能节省时间。<br/><br/>在C++中extern还有另外一种作用,用于指示C或者C++函数的调用规范。比如在C++中调用C库函数,就需要在C++程序中用extern “C”声明要引用的函数。这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。主要原因是C++和C程序编译完成后在目标代码中命名规则不同,用此来解决名字匹配的问题。 |
|
||||
|
||||
#### C/C++特有---宏定义和展开、内联函数区别
|
||||
|
||||
**内联函数是代码被插入到调用者代码处的函数**。如同 #define 宏,内联函数通过避免被调用的开销来**提高执行效率**,尤其是它能够通过调用(“过程化集成”)被编译器优化。 **宏定义不检查函数参数,返回值什么的,只是展开,相对来说,内联函数会检查参数类型,所以更安全。** 内联函数和宏很类似,而区别在于,**宏是由预处理器对宏**进行替代,而**内联函数是通过编译器控制**来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。
|
||||
|
||||
宏是预编译器的输入,然后宏展开之后的结果会送去编译器做语法分析。宏与函数等处于不同的级别,操作不同的实体。宏操作的是 token, 可以进行 token的替换和连接等操作,在语法分析之前起作用。而函数是语言中的概念,会在语法树中创建对应的实体,内联只是函数的一个属性。
|
||||
对于问题:有了函数要它们何用?答案是:一:函数并不能完全替代宏,有些宏可以在当前作用域生成一些变量,函数做不到。二:内联函数只是函数的一种,内联是给编译器的提示,告诉它最好把这个函数在被调用处展开,省掉一个函数调用的开销(压栈,跳转,返回)
|
||||
|
||||
内联函数也有一定的局限性。就是函数中的执行代码不能太多了,如果,内联函数的函数体过大,一般的编译器会放弃内联方式,而采用普通的方式调用函数。这样,内联函数就和普通函数执行效率一样
|
||||
|
||||
内联函数必须是和函数体申明在一起,才有效。
|
||||
|
||||
[宏定义和内联函数区别](http://www.cnblogs.com/chengxuyuancc/archive/2013/04/04/2999844.html)
|
||||
|
||||
# STL原理及实现
|
||||
|
||||
> Java中集合类(接口collection的子类)、map接口
|
||||
|
||||
STL提供六大组件,彼此可以组合套用:
|
||||
|
||||
> 1、容器(Containers):各种数据结构,如:序列式容器vector、list、deque、关联式容器set、map、multiset、multimap。用来存放数据。从实现的角度来看,STL容器是一种class template。
|
||||
|
||||
> 2、算法(algorithms):各种常用算法,如:sort、search、copy、erase。从实现的角度来看,STL算法是一种 function template。注意一个问题**:任何的一个STL算法,都需要获得由一对迭代器所标示的区间,用来表示操作范围**。这一对迭代器所标示的区间都是前闭后开区间,例如[first, last)
|
||||
|
||||
> 3、迭代器(iterators):容器与算法之间的胶合剂,**是所谓的“泛型指针”**。共有五种类型,以及其他衍生变化。从实现的角度来看,迭代器是一种将 operator*、operator->、operator++、operator- - 等指针相关操作进行重载的class template。所有STL容器都有自己专属的迭代器,只有容器本身才知道如何遍历自己的元素。原生指针(native pointer)也是一种迭代器。
|
||||
|
||||
> 4、仿函数(functors):行为类似函数,可作为算法的某种策略(policy)。从实现的角度来看,仿函数是一种重载了operator()的class或class template。一般的函数指针也可视为狭义的仿函数。
|
||||
|
||||
> 5、配接器(adapters):一种用来修饰容器、仿函数、迭代器接口的东西。例如:STL提供的queue 和 stack,虽然看似容器,但其实只能算是一种容器配接器,因为它们的底部完全借助deque,所有操作都由底层的deque供应。改变 functors接口者,称为function adapter;改变 container 接口者,称为container adapter;改变iterator接口者,称为iterator adapter。
|
||||
|
||||
> 6、配置器(allocators):负责空间配置与管理。从实现的角度来看,**配置器是一个实现了动态空间配置、空间管理、空间释放的class template**。
|
||||
|
||||
这六大组件的交互关系:container(容器) 通过 allocator(配置器) 取得数据储存空间,algorithm(算法)通过 iterator(迭代器)存取 container(容器) 内容,functor(仿函数) 可以协助 algorithm(算法) 完成不同的策略变化,adapter(配接器) 可以修饰或套接 functor(仿函数)
|
||||
|
||||
序列式容器:
|
||||
vector-数组,元素不够时再重新分配内存,拷贝原来数组的元素到新分配的数组中。
|
||||
list-单链表。
|
||||
deque-分配中央控制器map(并非map容器),map记录着一系列的固定长度的数组的地址.记住这个map仅仅保存的是数组的地址,真正的数据在数组中存放着.deque先从map中央的位置(因为双向队列,前后都可以插入元素)找到一个数组地址,向该数组中放入数据,数组不够时继续在map中找空闲的数组来存数据。当map也不够时重新分配内存当作新的map,把原来map中的内容copy的新map中。所以使用deque的复杂度要大于vector,尽量使用vector。
|
||||
|
||||
stack-基于deque。
|
||||
queue-基于deque。
|
||||
heap-完全二叉树,使用最大堆排序,以数组(vector)的形式存放。
|
||||
priority_queue-基于heap。
|
||||
slist-双向链表。
|
||||
|
||||
关联式容器:
|
||||
set,map,multiset,multimap-基于红黑树(RB-tree),一种加上了额外平衡条件的二叉搜索树。
|
||||
|
||||
hash table-散列表。将待存数据的key经过映射函数变成一个数组(一般是vector)的索引,例如:数据的key%数组的大小=数组的索引(一般文本通过算法也可以转换为数字),然后将数据当作此索引的数组元素。有些数据的key经过算法的转换可能是同一个数组的索引值**(碰撞问题,可以用线性探测,二次探测来解决**),STL是用开链的方法来解决的,每一个数组的元素维护一个list,他把相同索引值的数据存入一个list,这样当list比较短时执行删除,插入,搜索等算法比较快。
|
||||
|
||||
hash_map,hash_set,hash_multiset,hash_multimap-基于hashtable。
|
||||
|
||||
[STL六大组件] (http://blog.csdn.net/chenguolinblog/article/details/30336805)
|
||||
什么是“标准非STL容器”?
|
||||
|
||||
list和vector有什么区别?
|
||||
|
||||
> vector拥有一段连续的内存空间,因此支持随机存取,如果需要高效的随即存取,而不在乎插入和删除的效率,使用vector。
|
||||
> list拥有一段不连续的内存空间,因此不支持随机存取,如果需要大量的插入和删除,而不关心随即存取,则应使用list。
|
||||
|
||||
# 虚函数
|
||||
|
||||
C++的多态分为静态多态(编译时多态)和动态多态(运行时多态)两大类。静态多态通过重载、模板来实现;动态多态就是通过本文的主角虚函数来体现的。
|
||||
|
||||
虚函数实现原理:包括虚函数表、虚函数指针等
|
||||
|
||||
虚函数的作用说白了就是:当调用一个虚函数时,被执行的代码必须和调用函数的对象的动态类型相一致。编译器需要做的就是如何高效的实现提供这种特性。不同编译器实现细节也不相同。大多数编译器通过vtbl(virtual table)和vptr(virtual table pointer)来实现的。 当一个类声明了虚函数或者继承了虚函数,这个类就会有自己的vtbl。vtbl实际上就是一个函数指针数组,有的编译器用的是链表,不过方法都是差不多。vtbl数组中的每一个元素对应一个函数指针指向该类的一个虚函数,同时该类的每一个对象都会包含一个vptr,vptr指向该vtbl的地址。
|
||||
|
||||
|
||||
|
||||
C/C++的具体总结可看[cpp-backend-reference/back-end.md at master · chankeh/cpp-backend-reference (github.com)](https://github.com/chankeh/cpp-backend-reference/blob/master/back-end.md)
|
||||
|
Loading…
x
Reference in New Issue
Block a user