(如果一个人夸你,千万别相信,一个人真优秀是不需要说出来的,所以别人夸你的时候也是自己最松懈的时候,千万不能飘,只能说明自己不是很差而已,世界上优秀的人很多,一直优秀到最后的人却是凤毛菱角。

如果一个人批评你时,却值得注意,一群人真心的批评你是,就要自己好好思考一下,跟别人聊聊,求求心得,如果还是觉得自己对,就带动大家一起干吧,证明给自己看! 要么自己错了,要么坚持,都离不开团队)。

参考:

1.C++ Virtual详解 :http://www.cnblogs.com/xd502djj/archive/2010/09/22/1832912.html

2.c++   __stdcall 的使用:https://blog.csdn.net/fu_zk/article/details/19126301

                                           https://blog.csdn.net/qq_15267341/article/details/79995021

知识:

1.C++ Virtual详解 

 

Virtual是C++ OO机制中很重要的一个关键字。只要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在Base的派生类Derived中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。当基类Base的指针point指向派生类Derived的对象时,对point的print函数的调用实际上是调用了Derived的print函数而不是Base的print函数。这是面向对象中的多态性的体现。(关于虚拟机制是如何实现的,参见Inside the C++ Object Model ,Addison Wesley 1996) class Base { public:Base(){} public:        virtual void print(){cout<<"Base";} };   class Derived:public Base { public:Derived(){} public:        void print(){cout<<"Derived";} };   int main() {        Base *point=new Derived();        point->print(); }

Output: Derived 这也许会使人联想到函数的重载,但稍加对比就会发现两者是完全不同的: (1)       重载的几个函数必须在同一个类中; 覆盖的函数必须在有继承关系的不同的类中 (2)       覆盖的几个函数必须函数名、参数、返回值都相同; 重载的函数必须函数名相同,参数不同。参数不同的目的就是为了在函数调用的时候编译器能够通过参数来判断程序是在调用的哪个函数。这也就很自然地解释了为什么函数不能通过返回值不同来重载,因为程序在调用函数时很有可能不关心返回值,编译器就无法从代码中看出程序在调用的是哪个函数了。 (3)       覆盖的函数前必须加关键字Virtual; 重载和Virtual没有任何瓜葛,加不加都不影响重载的运作。   关于C++的隐藏规则: 我曾经听说过C++的隐藏规则: (1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)。 (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。 #include <iostream.h> class Base { public: virtual void f(float x){ cout << "Base::f(float) " << x << endl; } void g(float x){ cout << "Base::g(float) " << x << endl; } void h(float x){ cout << "Base::h(float) " << x << endl; } };   class Derived : public Base { public: virtual void f(float x){ cout << "Derived::f(float) " << x << endl; } void g(int x){ cout << "Derived::g(int) " << x << endl; } void h(float x){ cout << "Derived::h(float) " << x << endl; } };   void main(void) { Derived d; Base *pb = &d; Derived *pd = &d; // Good : behavior depends solely on type of the object pb->f(3.14f); // Derived::f(float) 3.14 pd->f(3.14f); // Derived::f(float) 3.14 // Bad : behavior depends on type of the pointer pb->g(3.14f); // Base::g(float) 3.14 pd->g(3.14f); // Derived::g(int) 3 (surprise!) // Bad : behavior depends on type of the pointer pb->h(3.14f); // Base::h(float) 3.14 (surprise!) pd->h(3.14f); // Derived::h(float) 3.14 }   bp 和dp 指向同一地址,按理说运行结果应该是相同的,而事实上运行结果不同,所以他把原因归结为C++的隐藏规则,其实这一观点是错的。决定bp和dp调用函数运行结果的不是他们指向的地址,而是他们的指针类型。“只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用”(C++ Primer 3rd Edition)。pb是基类指针,pd是派生类指针,pd的所有函数调用都只是调用自己的函数,和多态性无关,所以pd的所有函数调用的结果都输出Derived::是完全正常的;pb的函数调用如果有virtual则根据多态性调用派生类的,如果没有virtual则是正常的静态函数调用,还是调用基类的,所以有virtual的f函数调用输出Derived::,其它两个没有virtual则还是输出Base::很正常啊,nothing surprise! 所以并没有所谓的隐藏规则,虽然《高质量C++/C 编程指南》是本很不错的书,可大家不要迷信哦。记住“只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用”。   纯虚函数: C++语言为我们提供了一种语法结构,通过它可以指明,一个虚拟函数只是提供了一个可被子类型改写的接口。但是,它本身并不能通过虚拟机制被调用。这就是纯虚拟函数(pure virtual function)。 纯虚拟函数的声明如下所示: class Query { public: // 声明纯虚拟函数 virtual ostream& print( ostream&=cout ) const = 0; // ... }; 这里函数声明后面紧跟赋值0。 包含(或继承)一个或多个纯虚拟函数的类被编译器识别为抽象基类。试图创建一个抽象基类的独立类对象会导致编译时刻错误。(类似地通过虚拟机制调用纯虚拟函数也是错误的例如) // Query 声明了纯虚拟函数 // 所以, 程序员不能创建独立的 Query 类对象 // ok: NameQuery 中的 Query 子对象 Query *pq = new NameQuery( "Nostromo" ); // 错误: new 表达式分配 Query 对象 Query *pq2 = new Query; 抽象基类只能作为子对象出现在后续的派生类中。   如果只知道virtual加在函数前,那对virtual只了解了一半,virtual还有一个重要用法是virtual public,就是虚拟继承。虚拟继承在C++ Primer中有详细的描述,下面稍作修改的阐释一下: 在缺省情况下C++中的继承是“按值组合”的一种特殊情况。当我们写 class Bear : public ZooAnimal { ... }; 每个Bear 类对象都含有其ZooAnimal 基类子对象的所有非静态数据成员以及在Bear中声明的非静态数据成员类似地当派生类自己也作为一个基类对象时如: class PolarBear : public Bear { ... }; 则PolarBear 类对象含有在PolarBear 中声明的所有非静态数据成员以及其Bear 子对象的所有非静态数据成员和ZooAnimal 子对象的所有非静态数据成员。在单继承下这种由继承支持的特殊形式的按值组合提供了最有效的最紧凑的对象表示。在多继承下当一个基类在派生层次中出现多次时就会有问题最主要的实际例子是iostream 类层次结构。ostream 和istream 类都从抽象ios 基类派生而来,而iostream 类又是从ostream 和istream 派生 class iostream :public istream, public ostream { ... }; 缺省情况下,每个iostream 类对象含有两个ios 子对象:在istream 子对象中的实例以及在ostream 子对象中的实例。这为什么不好?从效率上而言,存储ios 子对象的两个复本,浪费了存储区,因为iostream 只需要一个实例。而且,ios 构造函数被调用了两次每个子对象一次。更严重的问题是由于两个实例引起的二义性。例如,任何未限定修饰地访问ios 的成员都将导致编译时刻错误:到底访问哪个实例?如果ostream 和istream 对其ios 子对象的初始化稍稍不同,会怎样呢?怎样通过iostream 类保证这一对ios 值的一致性?在缺省的按值组合机制下,真的没有好办法可以保证这一点。 C++语言的解决方案是,提供另一种可替代按“引用组合”的继承机制虚拟继承(virtual inheritance )在虚拟继承下只有一个共享的基类子对象被继承而无论该基类在派生层次 中出现多少次共享的基类子对象被称为虚拟基类。        通过用关键字virtual 修政一个基类的声明可以将它指定为被虚拟派生。例如,下列声明使得ZooAnimal 成为Bear 和Raccoon 的虚拟基类: // 关键字 public 和 virtual // 的顺序不重要 class Bear : public virtual ZooAnimal { ... }; class Raccoon : virtual public ZooAnimal { ... }; 虚拟派生不是基类本身的一个显式特性,而是它与派生类的关系如前面所说明的,虚拟继承提供了“按引用组合”。也就是说,对于子对象及其非静态成员的访问是间接进行的。这使得在多继承情况下,把多个虚拟基类子对象组合成派生类中的一个共享实例,从而提供了必要的灵活性。同时,即使一个基类是虚拟的,我们仍然可以通过该基类类型的指针或引用,来操纵派生类的对象。

2.c++   __stdcall 的使用

__stdcall用来修饰函数,被该关键字修饰的函数,其参数都是从右向左依次被压入到栈中,函数调用在返回前需要清理堆栈,被调函数在返回前负责清理堆栈。

 

函数调用约定

    函数调用约定主要约束了两件事:
1. 参数传递的顺序
2. 调用堆栈由谁(调用函数或被调用函数)负责清理
 
    __stdcall是函数调用约定的一种。__stdcall表示:
1. 参数从右向左压入堆栈(这样当函数参数出栈时,刚好是先拿到最左边的参数)
2. 函数被调用者修改堆栈,负责清理自己在堆栈中的参数
3. 函数名(在编译器层次)自动加前导下划线,后面紧跟着一个@符号,其后紧跟着参数的尺寸。因此,声明为 int func( int a, int b ) 的函数修饰如下所示:_func@8
 
以上述这个函数为例,参数b首先被压栈,然后是参数a,函数调用function(1,2)调用处翻译成汇编语言将变成:
  push 2          第二个参数入栈

  push 1          第一个参数入栈

  call function   调用参数,注意此时自动把cs:eip入栈
而对于函数自身,则可以翻译为:
  push  ebp               保存ebp寄存器,该寄存器将用来保存堆栈的栈顶指针,可以在函数退出时恢复

  mov   ebp,esp           保存堆栈指针

  mov   eax,[ebp + 8H]    堆栈中ebp指向位置之前依次保存有ebp,cs:eip,a,b,ebp +8指向a

  add   eax,[ebp + 0CH]   堆栈中ebp + 12处保存了b

  mov   esp,ebp           恢复esp

  pop   ebp

  ret   8

而在编译时,这个函数的名字被翻译成_function@8

注意不同编译器会插入自己的汇编代码以提供编译的通用性,但是大体代码如此。其中在函数开始处保留esp到ebp中,在函数结束恢复是编译器常用的方法。

从函数调用看,2和1依次被push进堆栈,而在函数中又通过相对于ebp(即刚进函数时的堆栈指针)的偏移量存取参数。函数结束后,ret 8表示清理8个字节的堆栈,函数自己恢复了堆栈。

独立看第一个C++程序到最终结果log----2019-04-16的更多相关文章

  1. 独立看第一个C++程序到最终结果log----2019-04-15

    本文纯为本人记录,有网上诸多参考,请勿转发! 记录可能可能有点啰嗦,自己划重点吧!! (无论是生活还是工作,如果很困惑,千万不要消极一定要勇敢积极的面对它,不用说太多懂得人自然懂,一定要解决这个疑惑就 ...

  2. 1万字!彻底看懂微信小程序

    Q:为什么说小程序如炮友? A:小程序刚发布不久就流行一个段子:APP如原配,一年不用几次:服务号如情人,一个月固定几次:订阅号如酒店小卡片,天天可以卖广告:小程序像炮友,用完就走. 资本如嫖客,各个 ...

  3. 2、Spring的 IoC详解(第一个Spring程序)

    Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架.在这句话中重点有两个,一个是IoC,另一个是AOP.今天我们讲第一个IoC. IoC概念 ...

  4. Java起源、发展历程、环境变量、第一个Java程序等【1】

    若有不正之处,请多多谅解并欢迎批评指正,不甚感激. 请尊重作者劳动成果,转载请标明原文链接: 本文原创作者:pipi-changing 本文原创出处:http://www.cnblogs.com/pi ...

  5. 学了C语言,如何利用CURL写一个下载程序?—用nmake编译CURL并安装

    在这一系列的前一篇文章学了C语言,如何为下载狂人写一个磁盘剩余容量监控程序?中,我们为下载狂人写了一个程序来监视磁盘的剩余容量,防止下载的东西撑爆了硬盘.可是,这两天,他又抱怨他的下载程序不好用,让我 ...

  6. 你好,C++(3)2.1 一个C++程序的自白

    第2部分 与C++第一次亲密接触 在浏览了C++“三分天下”的世界版图之后,便对C++有了基本的了解,算是一只脚跨入了C++世界的大门.那么,怎样将我们的另外一只脚也跨入C++世界的大门呢?是该即刻开 ...

  7. 做为一个Java程序员,你需要哪些傍身的技能?

    最近总有些断断续续的思考,想想从我入行以来,我到底学会了什么,做成过什么,以后要做什么,如何提升自己······· 工作3年了,常听人说3年,5年,10年是程序员的坎,每过一个都会有新的想法,新的改变 ...

  8. 编译:一个 C 程序的艺术之旅(转载)

    C 程序为什么要编译才能执行?一个 C 程序在变成可执行文件的过程中,为什么要经过预处理.编译.汇编.链接这四道工序?让我们从这段简单的 C 程序开始. 为什么要编译 这并不是一个简单的问题.我们知道 ...

  9. JFinal教程1——小白的第一个JFinal程序

    为了使小白能够完全的按步骤创建第一个JFinal应用并运行,笔者将以Java界最流行的Eclipse平台为例,搭建出所有基础教程中喜欢的Hello world应用. 1. JFinal简介 2. 小白 ...

随机推荐

  1. Labview学习之路(五)按钮的机械动作

    布尔类型中有一个按钮是非常重要的控件,他不是只是表示一个确定,输出0或1,下边我们共同探讨一下他的机械动作 单击时转换 释放时转换 保持转换直到释放 单击时触发 释放时触发 保持触发直到释放 单击时转 ...

  2. Android Studio 如何导出和导入自己的常用设置,避免重复制造轮子。加快开发速度

    Android Studio 如何导出和导入自己的常用设置,避免重复制造轮子.加快开发速度 作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 在使用 A ...

  3. 只有一重循环的排序——侏儒排序(Gnome Sort)

    侏儒排序:从头(i=0)开始遍历元素,如果当前元素比前一个元素大(array[i]>array[i-1]),就把它跟前一个元素互换(Swap(a[i],a[i-1]))并继续检查它(i--),否 ...

  4. maven踩过的坑

    maven配置 maven默认配置 解决每次打开idea的spring项目都需要重新配置maven,选择file/other settings/preference for new projects ...

  5. 反射机制(Java)

    反射机制 今天闲来无事,对反射机制http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html阅读一番,整理了下这方面的知识以及自己的一些心得 ...

  6. 【问题】【SpringBoot】记一次springboot框架下用jackson解析RequestBody失败的问题

    最近项目中遇到了一个问题,费好大劲才发现问题所在,并且修复了问题,下面分享一下这个问题的定位和修复的新路旅程. 先说下背景:该项目用的是SpringBoot框架,主要功能为对外提供一些Restful ...

  7. 学习python你必须弄懂的 Python、Pycharm、Anaconda 三者之间的关系

    Python作为深度学习和人工智能学习的热门语言,学习一门语言,除了学会其简单的语法之外还需要对其进行运行和实现,才能实现和发挥其功能和作用.下面来介绍运行Python代码常用到的工具总结. 一.Py ...

  8. Agumaster 增加股票表台账页面

  9. [Java数据结构]LinkedHashMap,TreeMap

    HashMap不能记住插入时的顺序,但LinkedHashMap可以做到这一点. 例程: Map<Integer,String> empMap=new LinkedHashMap<I ...

  10. [LeetCode]621. 任务调度器(贪心)

    题目 给定一个用字符数组表示的 CPU 需要执行的任务列表.其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务.任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完.CP ...