虚表与重写
虚表:在C++语言中,每个有虚函数的类或者虚继承的子类,编译器都会为它生成一个虚拟函数表(简称:虚表),表中的每一个元素都指向一个虚函数的地址。(注意:虚表是从属于类的)
此外,编译器会为包含虚函数的类加上一个成员变量,是一个指向该虚函数表的指针(常被称为vptr),每一个由此类别派生出来的类,都有这么一个vptr。虚表指针是从属于对象的。也就是说,如果一个类含有虚表,则该类的所有对象都会含有一个虚表指针,并且该虚表指针指向同一个虚表。
虚表的内容是依据类中的虚函数声明次序--填入函数指针。派生类别会继承基础类别的虚表(以及所有其他可以继承的成员),当我们在派生类中改写虚函数时,虚表就受了影响;表中的元素所指的函数地址将不再是基类的函数地址,而是派生类的函数地址。
说人话就是:含有虚函数的类系统会为其维护一个大小为4字节的虚表指针,指向存放本类的虚函数表,表中存放着本类继承或者重写过的虚函数.
虚函数与重载差异虚函数:允许子类对父类方法进行重写,如果用一个基类指针指向一个派生类对象时虚表指针指向的是派生类的虚表。(动态联编)
123456789101112131415161718192 ...
文件io
C/C++文件IO版权
12345678910111213#include <vector>#include <algorithm>#include <iostream>#include "test.h"using namespace std;typedef struct Sys_Info{ unsigned int vesion; unsigned int sub_version; char info[20]; char date[20];} Sys_Info;12345678910111213
1. 基于C的流式文件操作
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970/*------operator file in the way of C stream-------- ...
constOpeartor
C++const和operator关键字const 类12345678910111213141516171819class Test{ public: int value = 1; void getvalue() const{ // this->value = 2;//wrong,常成员函数不可修改成员变量 } void setvalue(){ this->value = 2;//true }};void test(){ const Test name; //name.value = 10;//wrong,不可修改 // Cannot assign to variable 'name' with const-qualified type 'const Test' // name.setvalue();//wrong常量类不可执行非常量函数 //'this' arg ...
Static静态类型和this指针
Static静态类型和this指针Static静态类型详解 1):修饰全局变量时,表明一个全局变量只对定义在同一文件中的函数可见。
2):修饰局部变量时,表明该变量的值不会因为函数终止而丢失。
3):修饰函数时,表明该函数只在同一文件中调用。(这里指的同一文件不包括头文件包含的方式)
c++独有:
4):修饰类的数据成员,表明对该类所有对象这个数据成员都只有一个实例。即该实例归 所有对象共有。
5):用static修饰不访问非静态数据成员的类成员函数。这意味着一个静态成员函数只能访问它的参数、类的静态数据成员和全局变量
单指C中static1):1. 静态局部变量:用于函数体内部修饰变量,这种变量的生存期长于该函数。(static放在全局区,function放在栈区,函数结束时收回资源)
123456int foo(){ static int i = 1; // note:1 //int i = 1; // note:2 i += 1; return i;}
2.静态全局变量:定义在函数体外,用于修饰全局变量,表示 ...
inline
内联函数使用函数能够避免将相同代码重写多次的麻烦,还能减少可执行程序的体积,但也会带来程序运行时间上的开销。
函数调用在执行时,首先要在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,接下来还要将函数的返回地址(该地址指明了函数执行结束后,程序应该回到哪里继续执行)放入栈中,最后才跳转到函数内部执行。这个过程是要耗费时间的。
另外,函数执行 return 语句返回时,需要从栈中回收形参和局部变量占用的存储空间,然后从栈中取出返回地址,再跳转到该地址继续执行,这个过程也要耗费时间。
总之,使用函数调用语句和直接把函数中的代码重新抄写一遍相比,节省了人力,但是带来了程序运行时间上的额外开销。
一般情况下,这个开销可以忽略不计。但是,如果一个函数内部没有几条语句,执行时间本来就非常短,那么这个函数调用产生的额外开销和函数本身执行的时间相比,就显得不能忽略了。假如这样的函数在一个循环中被上千万次地执行,函数调用导致的时间开销可能就会使得程序运行明显变慢。
作为特别注重程序执行效率,适合编写底层系统软件的高级程序设计语言,C++ 用 inline 关键字较好地解决了函数调用开销的 ...
位运算
位运算&按位与运算通常用来判断某位的值是否为0或者将某个数的低几位置0。使用时得注意数据类型的size大小
1234567891011121314void and_test(void){ int int_num = 17; char char_num = 127; printf("int_num & 7 value = %d\n",int_num & 7); printf("int_num & 0xfffffff0 = %d\n",int_num & 0xfffffff0); printf("int_num & 7 value = %d\n",char_num & 7); printf("int_num & 0xf0 = %d\n",char_num & 0xf0);}/*int_num & 7 value = 1int_num & 0xfffffff0 = 16i ...
CFunctionPointer
**C中函数指针的作用 **项目中用到了很多封装在struct中的函数指针,以前在MFC里面经常用到则个作为回调函数,还以为是微软设计的特色呢。在网上查了一下它的用法,做个总结。
::1)**提供调用的灵活性**。设计好了一个函数框架,但是设计初期并不知道自己的函数会被如何使用。比如C的”stdlib”中声明的qsort函数,用来对数值进行排序。显然,顺序还是降序,元素谁大谁小这些问题,库程序员在编写qsort的时候不可能决定。这些问题是要在用户调用这个函数的时候才能够决定。那边qsort如何保证通用性和灵活性呢?采用的办法是让函数的使用者来制定排序规则。于是调用者应该自己设计comparator函数,传给qsort函数。这就在程序设计初期保证了灵活性。尽管使用函数指针使得程序有些难懂,但是这样的牺牲还是值得的。
2)**提供封装性能**。有点面向对象编程的特点。比如设计一个栈结构
123456789typedef struct _c_stack{ int base_size; int point; int * base; ...
makefile的编写
编写的Makefile正确姿势为什么要编写makefile:makefile是指一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,也可以执行操作系统的命令。
一个基本的makefile应该包含哪些功能:生成目标文件,清理临时文件。
1.编写只有main.cpp的makefile首先写一段测试代码
12345678910111213141516171819#include "iostream"int find_max(int arr[],int size){ int max = 0; for(int i = 0; i < size; i++){ if(max < arr[i]) max = arr[i];} return max;}int main(){ int arr[6] = {1,8,5 ...
CPPvolatile
C++生僻字的基本作用与用法(volatile)volatilevolatile关键字是防止在共享的空间发生读取的错误。只保证其可见性,不保证原子性;使用volatile指每次从内存中读取数据,而不是从编译器优化后的缓存中读取数据,简单来讲就是防止编译器优化。
在单任务环境中,如果在两次读取变量之间不改变变量的值,编译器就会发生优化,会将RAM中的值赋值到寄存器中;由于访问寄存器的效率要高于RAM,所以在需要读取变量时,直接寄存器中获取变量的值,而不是从RAM中。
在多任务环境中,虽然在两次读取变量之间不改变变量的值,在一些情况下变量的值还是会发生改变,比如在发生中断程序或者有其他的线程。这时候如果编译器优化,依旧从寄存器中获取变量的值,修改的值就得不到及时的响应(在RAM还未将新的值赋值给寄存器,就已经获取到寄存器的值)。
要想防止编译器优化,就需要在声明变量时加volatile关键字,加关键字后,就在RAM中读取变量的值,而不是直接在寄存器中取值。
一个线程改变了变量的值,怎样让改变后的值对其它线程 visible。一般说来,volatile用在如下的几个地方:
中 ...
STL之operator
STL之操作符重载(operator)C++中规定不能重载的操作符有:运算符 **::**(作用域解析)、**.**(成员访问)、**.\***(通过成员指针的成员访问)及 **?:**(三元条件)。
不能创建新运算符,例如 ***\***、**<>** 或 **&|**。
运算符 **&&** 与 **||** 的重载失去短路求值。
重载的运算符 **->** 必须要么返回裸指针,要么(按引用或值)返回同样重载了运算符 **->** 的对象。
不可能更改运算符的优先级、结合方向或操作数的数量。
**&&**、**||** 和 **,**(逗号)在被重载时失去其特殊的定序性质,并且即使不使用函数调用记法,也表现为与常规的函数调用相似。
除了上述限制外,语言对重载运算符的所作所为或返回类型(它不参与重载决议)上没有其他任何制约,但通常期待重载的运算符表现尽可能与内建运算符相似:期待 operator+ 对其实参进行相加而非相乘,期待 operator= 进行赋值,如此等等。期待相关的运算符之间的表现也相似(operator+ ...