摘要:
1、_stdcall是Pascal方式清理C方式压栈,通常用于Win32 Api中,函数采用从右到左的压栈方式, 自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。int f(void *p) -->> _f@4(在外部汇编语言里可以用这个名字引用这个函数) 2、C调用约定(即用__cdecl关键字说明)(The C default calling convention)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数vararg的函数(如pr 阅读全文
摘要:
一、头文件(1)注意保护头文件,防止头文件被多重包含,所有的头文件都必须使用#ifndef、#define和#endif进行保护,书写格式如下<PROJECT>_<PATH>_<FILE>_H_,全部使用大写。例如:#ifndef FOO_H_,对应于foo.h头文件。(2)在头文件中尽量少的包含别的头文件,如果可以请使用前置声明代替包含头文件。包含过多的头文件将会产生较强的依赖性,一旦文件有所改变,将会导致所有文件的重新编译。因此,尽量少的包含别的头文件而是用前置声明。在头文件如何做到使用类Foo而无需访问类的定义?1) 将数据成员类型声明为Foo *或F 阅读全文
摘要:
C++primer的解释是这样的: 变量的定义(definition):用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义; 变量的声明(declaration):用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用extern关键字声明变量名而不定义它。 以上解释讲得还是比较清楚的,有分配空间的叫定义,没分配空间的叫声明。好吧,你不知道什么时候分配什么时候没分配。让我们换一种说法。 “定义也是声明”,这说明声明包括定义。所以诸如int a;extern int a;之类的一定是声明。那是不是定义还要接着往下看; 如果 阅读全文
摘要:
原来刚学数据库的时候,不知道数据库的备份和还原,就直接去拷贝数据库mdf和ldf文件,后来会了数据库的备份和还原,一直也就没有注意拷贝mdf和ldf带来的问题。现在需要参考原来拷贝的代码和数据库(拷贝的mdf和ldf文件),结果发现数据库还原不上了。我就在百度搜索,出来了不少相关网页,打开后发现基本都是一个相同解决方案,列出ABCDEFG或者12345几项去解决,可惜,不成功。那就继续搜索,幸好在微软的MSDN网站上找到了类似的文档,通过分离和附加来移动数据库。我是个菜鸟,不知道什么是分离、附加数据库,汗颜,粗略看了一下,似懂非懂,不过发现了附加移动的数据库就是通过mdf和ldf文件恢复(创建 阅读全文
摘要:
对象数组的构造:对象数据的构造一般有两种方式:静态和动态(1)静态分配 以string类为例,string a[10];就是以静态形式构造数据,这样的数组的个数是确定的不能修改的。 像这样的数组怎么进行构造和析构呢? 编译器在构造数组的时候会生成一个使用默认构造函数的数组构造函数arr_new(char *p,sizeof(string),int num,构造函数地址,析构函数地址);同样也会生成数组析构函数,形式类似。arr_del(char *p,sizeof(string),int num,析构函数地址); 若数组构造中间出现异常,该函数必须保证已构造的对象析构,然后释放内存。 ... 阅读全文
摘要:
虚拟继承下的对象构造:由于虚拟基类对象在子类中只能保持一个实例,那么,子类构造的时候调用父类的构造函数的时候必须保证虚拟基类对象不能够重复构造。那么,C++规定虚拟基类对象的构造只能是最外层的子类进行构造,浅层次的子类将不会在进行构造,保证了虚拟基类对象的唯一性。在虚拟继承体系下,子类的构造函数中必须做一个判断,设置一个标准位,用来判断虚拟基类对象是否已经构建,然后将该标志为传递给浅层次的子类,那么虚拟基类将不会再次构造。例如,编译器会为子类构造函数内部设置标志位Point3D::Point3D(Point3D *this,bool _most_derived){ if(_most_deri. 阅读全文
摘要:
类中函数的深度探索类中包含的函数主要有三种:static成员函数、nostatic成员函数、virtual成员函数。C++类中数据成员和成员函数的命名机制:数据成员的命名:在每个数据成员命名的时候编译器将该成员所属的类名也添加上,用来标志这个成员的来源范围。这样,继承类就可以与子类用相同的名字命名其成员,这样就不会产生二义性和冲突,但是对外界而言,通过继承类对象访问该名字,只会获取继承类的数据成员,因为根据命名查找机制,两个名字属于不同的作用域,继承类中的成员覆盖了子类中的成员,想要调用必须显示调用子类成员或在继承类作用域中使用using。(函数名相同)成员函数的命名:在同一个类中允许函数重载 阅读全文
摘要:
在学习完类对象的构造后,下面就需要学习类数据成员和函数成员的存取。编译器对于类对象的处理方式:(1)对于空类,编译器为该类添加一个char类型的成员,用来唯一标识该类在内存的位置(2)使用对齐机制,当一个类的内存字节数不足4的倍数将自动补充,目的是为了寻址的方便有些编译器对于空类的处理进行了优化处理,仅当该空类被继承的时候,空类对象在子类对象中不占用任何内存,单独空类的大小仍是1个字节,这样可能会避免对齐机制,优化了C++对象模型的内存空间。但是对于非空类,不处理和优化处理对于类对象的内存空间没有任何改变。例如:class A{};class X:public virtual A{};clas 阅读全文
摘要:
上一章讲过了关于类对象内存分布,对于nostatic数据将会放在对象内存空间中,static数据成员和nostatic、static函数成员将不会放在对象内存中,对于虚拟继承和含有虚函数的类来说,将会在对象内存中增加一个虚表指针,指向该类的虚表,其中虚表中将会存放虚函数的地址和虚拟基类的地址。一个类中只含有一个共享虚表(继承基类的虚表也是继承类的虚表,一般继承类的虚函数会存放在第一个基类的虚表中方便提取),对象中可以含有多个虚指针,继承至基类,除了直接虚拟继承的继承类才会产生新的vptr和虚表用于指示虚拟基类的位置。下面是如何构建类对象,即构造函数的深入探索。首先强调两个C++新手容易陷入的误 阅读全文
摘要:
在实际生产中,遇到一个复杂的类,如果能看出这个类的内存模型结构,那么以后的操作基本就没有难度的;所以说,学会分析一个类的内存模型,是每一个C++程序员必须要会的知识。(1)C++类封装和C中的结构体的区别C++的类封装是在C语言中的结构体的基础上构建起来的,C结构体只允许存在数据,而不会存在对数据的操作。C++语言中延承C语言中的结构体,但增加的对数据的操作,即成员函数;类是对结构体的进一步封装,使某些数据成员对外不可见,称为私有成员。类和结构体最大的区别就是:结构体成员均是public类型的。那么,类和结构体的布局成本有没有区别呢?对于只有数据成员的类和结构体在内存的布局是相同的,没有增加成 阅读全文