• 目录

    动态库,静态库区别(扩充知识点)

    静态链接与动态链接的区别(wyyx)

    解释内存对齐及其原理(wyyx)

    派生类虚表的布局是怎样的(wyyx)

    模板类了解吗?实现一个unique_list容器(插入操作)(代码,借助vector实现的)(wyyx)


    动态库,静态库区别(扩充知识点)

  1. 简单来说,动态库总是与应用程序编译在一起的,在任何情况下都能运行,不依赖外部的情况。而动态库是动态链接的,顾名思义就时在应用程序真正运行时才会链接。所以当用户的系统上没有该动态库时,应用程序就会运行失败(在Windows下就是缺少dll文件)。
  2. 多个程序可以共享一个动态库。当启动多个使用相同的动态库的应用程序时,只需要将动态库加载到内存一次就好了。相反,使用静态链接的应用程序一般都比较大,如果多个应用程序使用了相同的静态库,我们就需要将静态库多次装载到内存中,浪费内存。
  3. 静态链接应用程序一般执行速度较快,因为所需要的代码都放在可执行文件中了,而动态链接还需要在运行时动态调用动态库,因此速度略慢。
  4. 对于静态链接的应用程序,如果你的静态库发生了变化,那么整个程序都会需要重新编译,而动态链接的应用程序就没有这个问题,在保持接口不变的情况下,我们升级动态库不影响我们的应用程序,所以在这一点上动态库时格外的方便。

  • 静态链接与动态链接的区别(wyyx)

  1. 静态链接用到的是静态库,动态链接用到的是动态库。
  2. 最明显的区别:动态链接初始化速度比静态链接初始化速度快,但运行期速度比静态链接的速度慢。
  3. 静态链接对函数库的连接是放在编译期完成的,所有相关的对象文件与涉及到的函数库被链接为一个可执行文件程序运行期,与函数库再无瓜葛,因为我们所有需要的函数都已经在可执行文件之中了(这些函数库称为静态函数库)。
  4. 动态链接对函数库的链接并不是在编译期完成,而是在程序运行期真正到了调用动态库代码时,载入程序才计算(被调用的那部分)代码的逻辑地址,等到程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址。
  5. 多个程序可以共享一个动态库。当启动多个使用相同的动态库的应用程序时,只需要将动态库加载到内存一次就好了。相反,使用静态链接的应用程序一般都比较大,如果多个应用程序使用了相同的静态库,我们就需要将静态库多次装载到内存中,浪费内存。
  6. 对于静态链接的应用程序,如果你的静态库发生了变化,那么整个程序都会需要重新编译,而动态链接的应用程序就没有这个问题,在保持接口不变的情况下,我们升级动态库不影响我们的应用程序,所以在这一点上动态库时格外的方便。

  • 解释内存对齐及其原理(wyyx)

内存对其的目的:主要是为了提高处理效率。

内存对齐规则:对于struct(或union)的数据成员吗,按照成员的声明顺序,依次安排内存,其偏移量为成员大小的整数倍,最后结构体的大小为最大成员(和pragma pack指定数值,两者最小的值)的整数倍。

内存对齐的原因:

  1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的。
  2. 性能原因:数据结构(尤其是栈),应该尽可能地在自然边界上的对齐。为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问只需要一次访问。

举例:

typedef struct {int a;double b;short c;
}A;//sizeof(A) = 24typedef struct {int a;short b;double c;
}B;//sizeof(B) = 16

在结构体中,从结构体的首地址开始,假设地址从0开始。 
对结构体A来说,a占4个字节,占从0~3的字节,b是double类型占8个字节,占从8~15的字节,c占两个字节,从16~17的字节。 
对结构体B来说,a占4个字节,从0~3,b占两个字节从4~6;c占8个字节从8~15。 
这就是内存对齐,对齐规则是按照成员的声明顺序,依次安排内存,其偏移量为成员大小的整数倍,0看做任何成员的整数倍,最后结构体的大小为最大成员的整数倍(所以这里的A的大小是24,而不是18)。


  • 派生类虚表的布局是怎样的(wyyx)

  • 无继承情况
#include <iostream>using namespace std;class Base
{
public:Base(){cout<<"Base construct"<<endl;}virtual void f() {cout<<"Base::f()"<<endl;}virtual void g() {cout<<"Base::g()"<<endl;}virtual void h() {cout<<"Base::h()"<<endl;}virtual ~Base(){}
};int main()
{typedef void (*Fun)();  //定义一个函数指针类型变量类型 FunBase *b = new Base();//虚函数表存储在对象最开始的位置//将对象的首地址输出cout<<"首地址:"<<*(int*)(&b)<<endl;Fun funf = (Fun)(*(int*)*(int*)b);Fun fung = (Fun)(*((int*)*(int*)b+1));//地址内的值 即为函数指针的地址,将函数指针的地址存储在了虚函数表中了Fun funh = (Fun)(*((int *)*(int *)b+2));funf();fung();funh();cout<<(Fun)(*((int*)*(int*)b+4))<<endl; //最后一个位置为0 表明虚函数表结束 +4是因为定义了一个 虚析构函数delete b;return 0;
}

注意:在上面这个图中,虚函数表中最后一个节点相当于字符串的结束符,其标志了虚函数表的结束,在Codeblocks下打印为0。

Base::~Base()在Base::h()后边

  • 继承,无虚函数覆盖的情形
#include <iostream>
using namespace std;class Base {
public:virtual void f() { cout << "Base::f()" << endl; }virtual void g() { cout << "Base::g()" << endl; }virtual void h() { cout << "Base::h()" << endl; }
};class Derive: public Base {virtual void f1() { cout << "Derive::f1()" << endl; }virtual void g1() { cout << "Derive::g1()" << endl; }virtual void h1() { cout << "Derive::h1()" << endl; }
};int main()
{typedef void (*Fun)();Base *b = new Derive;cout << *(int*)b << endl;Fun funf = (Fun)(*(int*)*(int*)b);Fun fung = (Fun)(*((int*)*(int*)b + 1));Fun funh = (Fun)(*((int*)*(int*)b + 2));Fun funf1 = (Fun)(*((int*)*(int*)b + 3));Fun fung1 = (Fun)(*((int*)*(int*)b + 4));Fun funh1 = (Fun)(*((int*)*(int*)b + 5));funf(); // Base::f()fung(); // Base::g()funh(); // Base::h()funf1(); // Derive::f1()fung1(); // Derive::g1()funh1(); // Derive::h1()cout << (Fun)(*((int*)*(int*)b + 6));return 0;
}

从表上可以看出

1、虚函数按照声明的顺序放在表中。

2、父类的虚函数在子类的虚函数前面。

  • 继承,虚函数覆盖的情形
#include <iostream>
using namespace std;class Base {
public:virtual void f() { cout << "Base::f()" << endl; }virtual void g() { cout << "Base::g()" << endl; }virtual void h() { cout << "Base::h()" << endl; }
};class Derive: public Base {virtual void f() { cout << "Derive::f()" << endl; }virtual void g1() { cout << "Derive::g1()" << endl; }virtual void h1() { cout << "Derive::h1()" << endl; }
};int main()
{typedef void (*Fun)();Base *b = new Derive;cout << *(int*)b << endl;Fun funf = (Fun)(*(int*)*(int*)b);Fun fung = (Fun)(*((int*)*(int*)b + 1));Fun funh = (Fun)(*((int*)*(int*)b + 2));Fun fung1 = (Fun)(*((int*)*(int*)b + 3));Fun funh1 = (Fun)(*((int*)*(int*)b + 4));funf(); // Derive::f()fung(); // Base::g()funh(); // Base::h()fung1(); // Derive::g1()funh1(); // Derive::h1()cout << (Fun)(*((int*)*(int*)b + 5));return 0;
}

从表上可以看出:

1、覆盖的 f() 函数被放到虚函数表中原来父类虚函数的位置。

2、没有被覆盖的函数依旧。

3、可通过获取成员函数指针来调用成员函数(即时是private类型的成员函数),这就出现一定的安全问题。

  • 多继承情况
#include <iostream>
using namespace std;class Base1 {
public:virtual void f() { cout << "Base1::f()" << endl; }virtual void g() { cout << "Base1::g()" << endl; }virtual void h() { cout << "Base1::h()" << endl; }
};class Base2 {
public:virtual void f() { cout << "Base2::f()" << endl; }virtual void g() { cout << "Base2::g()" << endl; }virtual void h() { cout << "Base2::h()" << endl; }
};class Base3 {
public:virtual void f() { cout << "Base3::f()" << endl; }virtual void g() { cout << "Base3::g()" << endl; }virtual void h() { cout << "Base3::h()" << endl; }
};class Derive: public Base1,public Base2, public Base3 {virtual void f() { cout << "Derive::f()" << endl; }virtual void g1() { cout << "Derive::g1()" << endl; }
};int main()
{typedef void (*Fun)();Derive d;Base1 *b1 = &d;Base2 *b2 = &d;Base3 *b3 = &d;b1->f(); //Derive::f()b2->f(); //Derive::f()b3->f(); //Derive::f()b1->g(); //Base1::g()b2->g(); //Base2::g()b3->g(); //Base3::g()Fun b1fun = (Fun)(*(int*)*(int*)b1);Fun b2fun = (Fun)(*(int*)*((int*)b1+1));Fun b3fun = (Fun)(*(int*)*((int*)b1+2));b1fun(); // Derive::f()b2fun(); // Derive::f()b3fun(); // Derive::f()return 0;
}

从表上可以看出:

1、每个父类都有自己的虚函数表。

2、子类的成员函数被放到了第一个父类的表中。(所谓的第一个父类是按照声明的顺序来确定的)


  • 模板类了解吗?实现一个unique_list容器(插入操作)(代码,借助vector实现的)(wyyx)

小老弟研发之路面筋大汇总——关于C/C++(三)相关推荐

  1. 小老弟3.6研发面筋大汇总

    目录 谈谈对C++的看法 树的遍历 八大排序考点 数据库 谈谈全局变量 ISO有几层 Socket编程,epoll,select,poll是什么,用途 前端的jquery 怎么写的,还记得哪些关键字 ...

  2. 微信小程序 | IM交友聊天功能大汇总

  3. 【webpack系列】webpack小老弟打包大项目

    上集回顾: 话音刚落 ~ npm老大哥又来电话了[有大工程]. "喂,老大哥,对方啥阵形啊?" "4-4-2? 踢你的?" "行,马上带上大姨夫嗷,拜 ...

  4. 2019公众号引流小诀窍大汇总

    [导读]微信公众号红利期已经过去了,但微信公众号运营仍然是非常必要的.现在微信公众号引流没有那么容易了,很多公众号运营人员已经陷入困境了.这里我们就给大家汇总了公众号引流小诀窍,希望可以帮到大家. 公 ...

  5. java面试笔试题大汇总

    java面试笔试题大汇总 JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题 ...

  6. python3廖雪峰云-python3基础教程廖雪峰云_Python GUI库大汇总

    Python GUI库大汇总 所有程序都是基于命令行的,这序可能只有一些"专的计算机人士才会使用.例如前面编写的五等程序,恐怕只有程序员自己才愿意玩这么"糟糕"的游戏,很 ...

  7. 进阶阿里巴巴之路——招聘要求汇总

    进阶阿里巴巴之路--招聘要求汇总 30-50万 北京 1个月前 本科及以上2年以上经验普通话25-40岁 职位描述: 岗位职责: 一.服务器端高级java工程师(应用市场) - 手机应用发展部 - 北 ...

  8. 陈老师给你介绍半导体功率器件知识大汇总

    常用的半导体功率器件知识大汇总 电力电子器件(Power Electronic Device),又称为功率半导体器件,用于电能变换和电能控制电路中的大功率(通常指电流为数十至数千安,电压为数百伏以上) ...

  9. 2019校招面经大汇总

    2019校招面经大汇总 转载链接:https://www.nowcoder.com/discuss/90907?type=0&order=3&pos=24&page=1 [杭州 ...

  10. 中国互联网企业的研发之路——与腾讯研究院院长郑全战一席谈

    文 / 刘江 腾讯研究院是国内互联网企业中最早的研究机构之一.2012年恰逢腾讯研究院五周年,<程序员>杂志总编刘江访问了腾讯首席架构师兼研究院院长郑全战. 在高科技产业中,中国的互联网可 ...

最新文章

  1. 多媒体指令(灰度像素最大值)
  2. 误差向量幅度(EVM)介绍
  3. 原价买了二手机,我是如何做到的?
  4. ae这样设置导出比较快 480p比较适合快速看看demo的样子,注意tradeoff
  5. javaScript之数组Array
  6. python抽象基类的作用_Python:多态、鸭子模型和抽象基类
  7. 陶瓷移动在飞信版C++女程序员
  8. Virtualenv 相关
  9. python将一行作为字段_Python 变量代入,指定某一行截取输出字段
  10. L2-008 最长对称子串(马拉车 or 技巧暴力)
  11. 使用Strophe连接xmpp,轻松构建web即时聊天工具
  12. 从傅里叶变换的角度谈宿命论
  13. dcmtk读取DICOM并进行体绘制渲染
  14. MySQL子查询的优缺点_为什么MySQL不推荐使用子查询和join
  15. 易语言流程控制程序暂停开始继续
  16. MATLAB 3D玫瑰花绘制(内附旋转版本)
  17. Conflux v2.2.0 网络 Hardfork 升级公告
  18. 单场GMV翻了100倍,冷门品牌崛起背后的“通用法则”是什么?
  19. 无线传感器网络技术与应用课后习题部分答案
  20. 中小企业信贷风险补偿综合管理系统

热门文章

  1. 重积分的计算机应用开题报告,重积分的数值计算【信息科学与技术专业】【毕业设计 文献综述 开题报告】.docx...
  2. SAP系统架构和技术平台
  3. 2.6 Abbreviation( 缩 写)
  4. 叮咚叮咚,京东叮咚音箱Skill开发之路
  5. frm mysql触发器_使用mysqlfrm恢复frm表结构的方法
  6. Nagios:用门户邮箱+mailx+139邮箱实现实时短信报警
  7. linux twm_回到TWM Linux桌面基础知识
  8. OpenGL ES EGL eglCreateContext
  9. 在Mac系统下配置端口映射
  10. MAC系统查看端口,并关闭端口占用