函数指针

ProtoBuf 源码简析

て烟熏妆下的殇ゞ 提交于 2019-12-01 02:07:04
ProtoBuf项目描述:   Google Protocol Buffer简称protobuf,为高效的二进制序列化/反序列化协议(一般为google内部使用),不同于xml、json等,其更小巧、高效;avro、thrift等; 其可用于网络协议、数据存储等语言无关、平台无关、可扩展的序列化结构数据格式。只要按照特定条件可支持向前、向后兼容;目前提供了C++、Java、Python 三种语言的 API,这样各语言可以相互序列化和反序列化数据信息(事实上也可以自定义实现其他语言的API接口)。 在使用中,用户可根据自定义或引入数据结构(Message)文件*.proto;此后通过编译器protoc.exe编译该描述文件为指定语言的操作接口,而后将产生的操作接口文件 和libprotobuf.lib添加入项目中进行数据序列化和反序列化操作即可,产生的序列化后的信息可读性很差,此外反序列化也必须知道对应的数据结构描述文件*.proto, 否则无法正确地反序列化,也不再有意义,相对xml,json无法直接插入或修改数据信息内容; 以下仅对C++相关进行分析; 项目工程: gtest:google 白盒测试开源项目,主要用于单元测试,后面的gtest_main、tests项目; gtest_main:简单的对main函数以及testing::InitGoogleTest(&argc,

SGI-STL简记(六)-序列容器(deque)

元气小坏坏 提交于 2019-12-01 02:03:58
stl_deque.h : deque:一种具有双端插入和删除,可随机访问元素的容器,从首部或后插入或删除在常量时间内完成,从中间则需线性时间内完成; __deque_buf_size:获取队列节点缓冲区大小(工具函数),当数据元素类型字节size小于512时则为512/size,否则为1,(意味着节点容器上限为512字节或者是一个自定义类型元素大小的字节); _Deque_iterator:专用于deque容器的迭代器模板类;重声明常规类型以及迭代器类型和常量迭代器类型,迭代器分类为random_access_iterator_tag;此外声明了一个_Map_pointer指向数据元素的指针的指针; 数据成员: _M_cur:指向当前node节点容器元素的当前指针; _M_first:指向当前的node节点容器第一个元素的指针; _M_last:指向当前的node节点容器最后一个元素尾部的指针; _M_node:指向node节点容器指针的指针(其值为对应的map缓冲区的槽, 而槽的值即为对应node节点缓冲区首地址); 成员函数: _S_buffer_size:静态函数,获取当前元素类型下的节点容器缓冲区大小(内部调用__deque_buf_size),如int时,则获得大小为512/4(即128个元素); 无参构造函数初始化所有成员为空,带参构造函数T*x, _Map

SGI-STL简记(六)-序列容器(list)

女生的网名这么多〃 提交于 2019-12-01 02:03:50
stl_list.h : list:一个可从任意位置快速插入和删除元素的双向链表,可在常数时间内完成,但是取数据、查找等则需要线性时间; _List_node_base:链表节点基类struct,仅包含_M_next、_M_prev成员,其分别为指向当前节点基类类型的下一个、上一个节点的指针; _List_node:节点模板类,继承于_List_node_base,只是增加了一个数据成员_M_data,用以保存实际的node节点数据; _List_iterator_base:链表迭代器基类,所属迭代器类型为bidirectional_iterator_tag; 内部成员_M_node为当前迭代器指向的节点; _List_node_base构造函数参数类型_List_node_base,该值以初始化_M_node; _M_incr:调整当前迭代器所指的节点为该节点的下一个节点; _M_decr:调整当前迭代器所指的节点为该节点的上一个节点; 此外重载的operator==,operator!=比较操作符,其实际上是直接比较迭代器的_M_node成员(地址); _List_iterator:链表迭代器模板类,继承于_List_iterator_base; 该模板类重声明了多个常规类型;多个重载版本的构造函数以初始化迭代器; 此外重载了解引用、取指针操作符(返回为当前迭代器_M_node

const、volatile、mutable的用法

六眼飞鱼酱① 提交于 2019-11-30 17:15:47
const 、 volatile 、 mutable 的 用法 const 修饰普通变量和指针 const 修饰变量,一般有两种写法: const TYPE value; TYPE const value; 这两种写法在本质上是一样的。它的含义是: const 修饰的类型为 TYPE 的变量 value 是不可变的。对于一个非指针的类型 TYPE ,无论怎么写,都是一个含义,即 value 值不可变。 例如: const int nValue ; //nValue 是 const int const nValue ; //nValue 是 const 但是对于指针类型的 TYPE ,不同的写法会有不同情况: l 指针本身是常量不可变 (char*) const pContent; l 指针所指向的内容是常量不可变 const (char) *pContent; (char) const *pContent; l 两者都不可变 const char* const pContent; 识别 const 到底是修饰指针还是指针所指的对象,还有一个较为简便的方法,也就是沿着 * 号划一条线: 如果 const 位于 * 的左侧,则 const 就是用来修饰指针所指向的变量,即指针指向为常量; 如果 const 位于 * 的右侧, const 就是修饰指针本身,即指针本身是常量。 const

Qt 中的二进制兼容策略(简而言之就是地址不能变,剩下的就是让地址不变的技巧)

时光毁灭记忆、已成空白 提交于 2019-11-30 13:38:22
本文翻译自 Policies/Binary Compatibility Issues With C++ 二进制兼容的定义 如果程序从一个以前版本的库动态链接到新版本的库之后,能够继续正常运行,而不需要重新编译,那么我们就说这个库是二进制兼容的。 如果一个程序需要重新编译来运行一个新版本的库,但是不需要对程序的源代码进一步的修改,这个库就是源代码兼容的。 二进制兼容性可以节省很多麻烦。这使得为特定平台分发软件变得更加容易。如果不确保版本之间的二进制兼容性,人们将被迫提供静态链接的二进制文件。静态二进制文件不好,因为它们 浪费资源(尤其是内存) 不能让程序从库中错误修正或扩展中受益 如何确保二进制兼容 在确保二进制兼容的情况下,我们能做的操作: 增加非虚函数、signal/slots、构造函数 增加枚举到类中 在已经存在的枚举的最后添加枚举值 例外:如果这会导致编译器为枚举选择更大的底层类型,那么更改会导致二进制不兼容。需要注意的是,编译器有选择基础类型的余地,所以从 API 设计的角度来看,建议添加一个 Max 枚举,其中包含一个明确的最大值(=255 或 =1 << 15 等)来创建一个数字枚举数值的区间,使其无论如何能够保证适合所选择的底层类型。 重新实现在父非虚基类 (从当前类回溯第一个非虚基类)里定义的虚函数,但是这个不完全确保二进制兼容,所以尽量不要这么做 例外: C++

嵌入式C++测试题

早过忘川 提交于 2019-11-30 10:30:18
仅供学习,为嵌入式帝国做亿分之一的贡献吧,临近国庆,祝大家国庆节快乐哦 答案仅供参考吧 一、 选择题(共 80 分, 每题 2 分 ) ( 1 ) A ( 2 ) C ( 3 ) C ( 4 ) B ( 5 ) D ( 6 ) C ( 7 ) C ( 8 ) D ( 9 ) A ( 10 ) C ( 11 ) A (12) B (13) D (14) B (15) A ( 16 ) A ( 17 ) C ( 18 ) D ( 19 ) D ( 20 ) C ( 21 ) C ( 22 ) D ( 23 ) D ( 24 ) D ( 25 ) A ( 26 ) C (27) C (28) C (29) B (30) B ( 31 ) A ( 32 ) D ( 33 ) D ( 34 ) B ( 35 ) A ( 36 ) A ( 37 ) B ( 38 ) B ( 39 ) C ( 40 ) C 二、 填空题(每空 1 分, 共 20 分) 1. 构造函数 2. friend 保护和私有成员 3. 先基类在派生类 4. 单一继承 5. virtual 6. 静态多态性 动态多态性 7. 抽象类 8. 测试是否文件尾 9. 成员函数 10. try throw catch 11. 代码复用和泛型程序设计 12. 类的友元函数 13. 抛出异常 捕捉异常 14. template 15.

面试官: 聊一聊Babel

你。 提交于 2019-11-30 09:34:09
点击关注本 公众号 获取文档最新更新,并可以领取配套于本指南的 《前端面试手册》 以及 最标准的简历模板 . 前言 Babel 是现代 JavaScript 语法转换器,几乎在任何现代前端项目中都能看到他的身影,其背后的原理对于大部分开发者还属于黑盒,不过 Babel 作为一个工具真的有了解背后原理的必要吗? 如果只是 Babel 可能真没有必要,问题是其背后的原理在我们开发中应用过于广泛了,包括不限于: eslint jshint stylelint css-in-js prettier jsx vue-template uglify-js postcss less 等等等等,从模板到代码检测,从混淆压缩到代码转换,甚至编辑器的代码高亮都与之息息相关. 如果有兴趣就可以搞一些黑魔法: 前端工程师可以用编译原理做什么? 前置 Babel 大概分为三大部分: 解析: 将代码(其实就是字符串)转换成 AST( 抽象语法树) 转换: 访问 AST 的节点进行变换操作生成新的 AST 生成: 以新的 AST 为基础生成代码 我们主要通过打造一个微型 babel 来了解 babel 的基本原理,这个微型 babel 的功能很单一也很鸡肋,但是依然有400行代码,其实现细节与 babel 并不相同,因为我们省去了很多额外的验证和信息解析,因为单单一个兼容现代 JavaScript 语法的

c++中try catch的用法

梦想与她 提交于 2019-11-30 04:43:02
  在c++中,可以直接抛出异常之后自己进行捕捉处理,如:(这样就可以在任何自己得到不想要的结果的时候进行中断,比如在进行数据库事务操作的时候,如果某一个语句返回SQL_ERROR则直接抛出异常,在catch块中进行事务回滚(回滚怎么理解?))。 #include <iostream> #include <exception> using namespace std; int main () { try { throw 1; throw "error"; } catch(char *str) { cout << str << endl; } catch(int i) { cout << i << endl; } } 也可以自己定义异常类来进行处理: #include <iostream> #include <exception> using namespace std; //可以自己定义Exception class myexception: public exception { virtual const char* what() const throw() { return "My exception happened"; } }myex; int main () { try { if(true) //如果,则抛出异常; throw myex; } catch

golang 基础(二)

感情迁移 提交于 2019-11-30 02:44:04
接口 接口 -> 是一种 类型!!! 一种抽象的类型 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类型。 interface是一组method的集合,是duck-type programming的一种体现。 接口做的事情就像是定义一个协议(规则),只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。 不关心属性(数据),只关心行为(方法)。 为了保护你的Go语言职业生涯,请牢记接口(interface)是一种类型。 为什么要使用接口 type Cat struct{} func (c Cat) Say() string { return "喵喵喵" } type Dog struct{} func (d Dog) Say() string { return "汪汪汪" } func main() { c := Cat{} fmt.Println("猫:", c.Say()) d := Dog{} fmt.Println("狗:", d.Say()) } 上面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码,如果我们后续再加上猪、青蛙等动物的话,我们的代 码还会一直重复下去。那我们能不能把它们当成“能叫的动物”来处理呢?

C++传值和传引用

烈酒焚心 提交于 2019-11-30 00:37:10
传值参数 首先你肯定明白一个道理:当初始化一个非引用类型的变量时,初始值被拷贝给变量,此时对变量的改动不会涌向初始值 int n = 0; int i = 1; // i是n的副本 i = 42; // i的值改变,n的值不改变 传值参数的机理完全一样,由于 每次调用函数时都会重新创建它的形参,并用传入的实参对形参进行初始化 ,所以 函数对形参做的所有操作不会影响实参 ,如果我们想让函数改变我们传入的实参本身们就可以用到 指针形参 访问函数外部对象 指针形参 先看一段代码: int n = 0; int i = 1; int *p1 = &n; //p1指向n int *p2 = &i; //p2指向i *p1 = 42; //n的值改变,p1不变 p1 = p2 //现在p1指向了i,但是i和n的值都不变 当执行指针拷贝操作时,拷贝的是指针的值(地址),拷贝之后,两个指针是不同的指针,因为指针可以使我们间接地访问所指向的对象,所以通过指针可以修改对象的值 指针形参也差不都 // 接受一个int类型的指针,然后将指针所指向的对象置0 void reset(int* ip) { *ip = 0; // 改变指针ip所指向对象的值 ip = 0; // 只改变了ip的局部拷贝,实参未被改变 } void reset(int i) { i = 0; } int main() { int