CS-Notes/notes/Java与C++后端开发.md
HuaHero ad575d73d9
Add files via upload
积累Java与C++后端开发比较的知识点,便于多途径找岗位
2023-11-16 17:06:19 +08:00

81 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 关键字
| 关键字 | 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 />4C++中的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++的多态分为静态多态(编译时多态)和动态多态(运行时多态)两大类。静态多态通过重载、模板来实现;动态多态就是通过本文的主角虚函数来体现的。
虚函数实现原理:包括虚函数表、虚函数指针等
虚函数的作用说白了就是当调用一个虚函数时被执行的代码必须和调用函数的对象的动态类型相一致。编译器需要做的就是如何高效的实现提供这种特性。不同编译器实现细节也不相同。大多数编译器通过vtblvirtual table和vptrvirtual table pointer来实现的。 当一个类声明了虚函数或者继承了虚函数这个类就会有自己的vtbl。vtbl实际上就是一个函数指针数组有的编译器用的是链表不过方法都是差不多。vtbl数组中的每一个元素对应一个函数指针指向该类的一个虚函数同时该类的每一个对象都会包含一个vptrvptr指向该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)