1.编程风格
- 在判断的时候一般用‘A’==a,这样在编程中误将==写成=编译器会帮我们检查出来
2.类型转换
- float a=1.0;
- cout<<(int)a 输出1
- cout<<(int&)a输出1065353216 因为int 和float在内存中分布不同
3.判断一个数是否是2的N次幂
- !(X&(X-1))
4.以下代码功能(a&b)+((a^b)>>1)求a,b的平均数
- 第一项求ab相同位的一半,第二项取ab相异位的一半
5.不用判断语句判断ab谁大
- int max=((a+b)+abs(a-b))/2
- 不用中间变量交换两个变量
- a=a^b;
- b=a^b;
- a=a^b;
6.一般都遵循#define定义
- “可读”的常量以及一些宏语句的任务,而typedef则常用来定义关键字、冗长的类型的别名。
- typedef (int*) pINT;
- 以及下面这行:
- #define pINT2 int*
- 相同?实则不同!实践中见差别:pINT a,b;的效果同int *a; int *b;表示定义了两个整型指针变量。而pINT2 a,b;的效果同int *a, b;
- 与inline 函数比较,inline函数提供参数检查,这是define所不具备的
7.指针一般大小固定,为4个字节
- char p[]="a\n"里面包包含三个字节,其中‘\n’算一个
8.内存对齐
- 一般数据在内存中的位置最好是其长度的整数倍
- 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
- 2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;例如上面第二个结构体变量的地址空间。
- 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。例如上面第一个结构体变量。
- 一个空类的大小为1,对于一个空类,编译器会默认为其产生4个成员函数:构造函数,析构函数,拷贝构造函数和赋值函数。
- 函数(非virtural)是不占类的空间的他们跟普通函数一样在代码段
- 也就是说
- class A
- {
- public:
- void Fun();
- };
- 被编译成void Fun(A *this);这种形式了,
- 静态数据成员和静态成员函数时类的一部分,而不是对象的一部分
- 多重继承的空类大小仍然为1
- 类的大小有内部变量和函数指针组成,函数指针的大小为4
- 浅复制--对内部的成员对象调用其构造函数,但是对于指针和引用类的变量仅仅复制其值,而并不复制其指向的对象
- 使用浅复制可能造成复制的对象具有共享数据,在调用析构函数的时候会对同一块存储区进行两次释放,出错
以下写法错误int &a;const int a1;对引用申明的时候应该对其初始化,对于常量,如果不是外部变量对于const指针,在声明的时候可以不进行初始化,它存在的意义在于当我们需要一个指向const指针的时候const int a=10;int *p=&a; \\报错上面会报错,前面加上const int *p=&a便可以,需要说明的是const指针不一定一定要指向const对象,也可以是变量。const常量的初始化应该在构造函数中完成,如果不在初始化中完成那么应该为其加上static如class A{const int a=0;}就是错误的要么将a放到构造函数中去初始化,要么将其声明为static
- 在C语言中直接定义的结构体类型例如struct A{};并不像C++那样可以直接用A来声明变量的例如 A a;而必须struct A a,除非使用typedef
- 在C++中struct 可以包含方法
13.函数指针为 返回类型 (*f)(参数1,参数2...)
- 在声明指向数组的指针的时候,要给出维数如
- int (*p)[]=a;
- 类似于 float (**def)[10]这种指针
- 1.对它求值的结果应该是float
- 2.她是指向一个数组指针的指针,数组的维数为10,里面存放着float类型的元素
- int *p[10]声明的是一个大小为10的数组,里面存放着指向int类型的指针
14,重载和覆盖的区别
- 重载:编译器根据参数不同确定调用不同的参数,在编译的时候已经确定调用哪个函数了,静态---与多态没什么关系
- 覆盖:子类和父类的成员函数在名称参数值返回值上都相同,一父类指针调用的时候运行时才确定调用哪个,动态---多态体现
15.哈希表处理冲突的方法
1).开放定址
- 线性再探测:探测下一个槽,直到有空位为止
- 二次探测再散列:左右跳跃式查找空位
- 伪随机数探测:利用随机序列(3,5,9...)进行探测
2).再哈希
3).冲突的地方建立链表
4).建立公共溢出区
16.公有,保护,私有继承
- 公有继承:基类中公有,保护成员以不变的属性出现在派生类中,私有成员不被继承且不能被访问,对于派生类来说,可以访问基类的成员,但是派生类的对象则只能能访问其共有成员。
- 保护继承:基类中公有,保护成员都以保护的属性出现在派生类中,私有成员不被继承且不能被访问
- 私有继承:基类中公有,保护成员都以私有的属性出现在派生类中,私有成员不被继承且不能被访问,对于派生类来说,可以访问基类的成员,但是派生类的对象则不能
- 在继承时如果不显示说明,则默认私有继承
- 虚继承:在继承过程中如果一个类继承了多个类,而这些类中有公共的父类,那么就可以考虑用虚继承来减小其大小达到节省空间的效果。在多继承中如果有父类有公共的函数,在调用是可以加上限定符a.A::foo()
- 虚函数继承:编译器为每个含有虚函数的对象都分配一个虚函数表指针,用以区别多态下调用哪个函数。
bb b;
cc c;
dd d;
int test;
aa *pa=&c;
//被注释的语句是错误的
test=b.pub;
//test=b.pro;
//test=b.pri;
test=b.GETPUB();
test=b.GETPRO();
//test=b.GETPRI();
b.pub=1;
//test=c.pub;
//test=c.pro;
//test=c.pri;
test=c.GETPUB();
test=c.GETPRO();
//test=c.GETPRI();
pa->pro=0;
//test=d.pub;
//test=d.pro;
//test=d.pri;
test=d.GETPUB();
test=d.GETPRO();
//test=d.GETPRI();
18.C++中比较的时候如果两边的数据类型不同,会有一个隐含的类型转换
cc* pc=new cc;
bb *pb=dynamic_cast<bb *>(pc);
aa *pa=dynamic_cast<aa *>(pc);
其中cc同时继承aa,bb,如果判断pb==pa,则会有一个将pa转换为pb的过程,如果是(int)pa==(int)pb,则不相等
19.大小端模式
所谓的大端模式,是指数据的高位,保存在内存的低地址中,而数据的低位,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
所谓的小端模式,是指数据的高位保存在内存的高地址中,而数 据的低位保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
20.负数的二进制表示
负数的二进制表示是其绝对值对应的原码取反然后加1得到的结果,以8位字长-1为例
1的绝对值 0000 0001 取反 1111 1110 ,然后加一有 1111 1111,故为0XFF