- bool类型
取值:true,false。
大小:VC占1个字节。 - const限定符
常量(常变量)声明形式:
const 数据类型 常量名=常量值;数据类型 const 常量名=常量值;
注:上面两者等价。
例子说明:
#include <iostream> using namespace std; int main(void) { //const int a; Error,常量必须初始化 const int a = 100; //a = 200; Error,常量不能重新被赋值 int b = 22; const int * p; //const在*左边,表示*p为常量,经由*p不能更改指针所指向的内容 p = &b; //*p = 200; Error,常量不能重新被赋值 //int * const p2; Error,p2为常量,常量必须初始化 int * const p2 = &b; //const在*右边,表示p2为常量 //int c =100; //p2 = &c; Error,常量不能重新被赋值 *p2 = 200; cout<<b<<endl; return 0; }
- const与#define
const定义的常量与#define定义的符号常量的区别:
前者有类型,要进行类型检查,后者只是单纯的替换;
前者在编译期分配内存,后者在预处理期替换,不分配内存;
作用域不同,前者的作用域与一般的变量的作用域相同,后者为定义处到程序结束,可以使用#undef取消。
#define容易产生副作用
//Effective C++ 3rd的一个例子。 #define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b)) int a = 5; int b = 0; CALL_WITH_MAX(++a, b); //a被累加二次 CALL_WITH_MAX(++a, b+10); //a被累加一次 // 在这里,调用f之前,a的递增次数竟然取决于“它被拿来和谁比较”
#include <iostream> using namespace std; //#define STR(a) a // 不使用#,使用STR(a),a未声明,会报错。 #define STR(a) #a // 字符串化,当这里使用#,你使用STR(a),a未声明,会被转化成字符串"a"。 #define CAT(a, b) a##b // 连接作用 int main() { int ab = 100; const char *str = STR(a); cout <<str << endl; //"a" cout << CAT(a, b) << endl; // 100 return 0; }
- 结构体对齐
什么是结构体对齐?
编译器为每个“数据单元”按排在某个合适的位置上。C、C++语言非常灵活,它允许你干涉“内存对齐”。
为什么要对齐?
性能原因:在对齐的地址上访问数据快。
对齐方法
1.第一个变量与结构体变量的偏移量为0;
2.计算每个变量的对齐数(编译器设置的对齐数与该成员大小的较小值);
3.每个成员变量 的地址为:对齐数的整数倍;对其到对齐数整数倍的地址;
4.结构体总大小为最大对齐数的整数倍。
对齐案例
// vc++默认对其整数为8,g++默认为4 // 在属性->C/C++->代码生成可以修改 // 或者 #pragma pack(8)修改 // #pragma pack()取消修改 /* struct MyStruct { char ch; // 0 double db; // 8 int it; // 16-23 }; // 24*/ /* struct MyStruct { char ch; // 0 int it; // 4 double db; // 8-15 }; // 16*/ /* struct MyStruct { char ch1; // 0 int it; // 4 char ch2; // 8 double db; // 16-23 }; // 24*/ struct MyStruct { double db1; //0 char ch1; //8 float ft; //12 int it; // 16 char ch2; // 20 double db2; // 24-31 }; // 32
-
域运算符作用:用于对与局部变量同名的全局变量进行访问;用于表示类的成员。
- new、delete运算符
new语法:
指针变量=new 数据类型(初始化参数-可选);
指针变量=new 数据类型[长度n];
delete语法:
delete 指针变量;
delete [] 指针变量;
new一个新对象过程:
内存分配(operator new)
调用构造函数
delete一个对象过程:
调用析构函数
释放内存(operator delete)
operator new/new operator/placement new:
operator new:只分配内存
new operator:调用构造函数 + 分配内存
placement new:不分配内存,调用拷贝构造函数 - 重载
函数重载:又称为函数的多态(静态多态),编译时期指定函数入口地址,静态联编。
成立条件:
形参数量不同;形参类型不同;形参的顺序不同;形参数量和形参类型都不同。派生类与基类通过虚函数实现的多态(动态多态),运行时期指定函数入口地址,动态联编。
注:函数重载跟函数的返回值无关。 -
name managling与extern “C”
name managling:就是将函数的名字修改,实现函数重载。
extern "C"使用:
#ifdef __cpluscplus extern “C” { #endif ... #ifdef __cpluscplus } #endif
- 带默认参数的函数
几点说明:
1.函数既有定义又有声明时,声明时指定后,定义后就不能再指定默认值;
2.默认值的定义必须遵守从右到左的顺序,如果某个形参没有默认值,则它左边的参数就不能有默认值;
3.函数调用时,实参与形参按从左到右的顺序进行匹配 - 引用
几点说明:
1.引用在定义的时候要进行初始化;
2.引用一经初始化,不能重新引用其他变量;
3.非const引用不能引用const常量;
4.double val3 = 3.14;const int& ref4 = val3;只是报警告,等价于定义一个临时变量int tmp = 3,然后让ref4去引用tmp,当ref4不是常引用的时候,编译器直接报类型转换错误(强类型)。
5.同理4,const int &ref = 10;常引用使用字面量初始化自然就是有效的。
6.不能返回对局部变量的引用,通过返回引用,可以让函数调用作为左值,改变全局或者静态变量的值(通常在函数中返回静态或者全局变量的引用)。
7.教课书上说的是引用不分配内存空间,但是不是与引用是使用指针实现的矛盾么? - 内联函数
几点说明:
1.不能有递归
2.不能包含静态数据
3.不能包含循环
4.不能包含switch和goto语句
5.不能包含数组
注:若一个内联函数定义不满足以上限制,则编译系统把它当作普通函数对待。
内联函数与带参数宏区别
一样是内联函数要进行类型检查,宏只是简单的替换。 - 类型转换
旧式转换
(T)exprT(expr)新式转换
const_cast<T>(expr)
void change(const int &r) { int &rr = const_cast<int &>(r); rr = 200; } void test(int &r) { r = 100; } int main(void) { int n = 100; const int *pn = &n; const int &rn = n; //const_cast一般用于指针或者引用 // 个人觉得const_cast应该应用到该场景 // 即变量本身是变量,但是被常量指针或者常引用引用了 // 希望通过指针,或者引用去修改最初变量的值 int *p = const_cast<int *>(pn); *p = 200; cout << n << endl; // 200 int &r = const_cast<int &>(rn); r = 300; cout << r << endl; const int val = 100; // 常量本身是不能更改的,最多你能更改它在内存中的值,当使用该常量时,它去常量表直接取值 // int varl = const_cast<int>(val); //Error, 无法从“const int”转换为“int” int m = 10; change(m); cout << m << endl; // 200 //使用const_cast去除const限定的目的不是为了修改它的内容 //使用const_cast去除const限定,通常是为了函数能够接受这个实际参数 const int a = 10; //test(a); // Error, 从“const int”转换为“int &” test(const_cast<int&>(a)); // 只是修改了a在内存中的值,a本身的值不会修改,在常量表中 return 0; }
static_cast<T>(expr)
理解成一般的强制转换即可。
reinterpret_cast<T>(expr)
“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。
int main(void) { int i; char *p = "This is a example."; i = reinterpret_cast<int>(p); //此时结果,i与p的值是完全相同的。 //cout << p << endl; // This is a example. cout << i << endl; // 13032560,cout 见int型,那么直接相当于printf的%d输出了他的地址 printf("%s\n", i); // This is a example. printf("%d\n", i); // 13032560 printf("%s\n", p); // This is a example. printf("%d\n", p); // 13032560 int m = 10; int *ip = &m; char *pc = reinterpret_cast<char*>(ip); // 程序员需要记得pc所指向的真实对象是int型,并非字符串。 // 如果将pc当作字符指针进行操作,可能会造成运行时错误 // 如int len = strlen(pc); printf("%d\n", *pc); // 10 return 0; }
dynamic_cast<T>(expr)
执行“安全向下”转型操作,也就是说支持运行时识别指针或所指向的对象,这是唯一个无法用旧式语来进行的转型操作。
转载于:https://www.cnblogs.com/ifpelset/articles/4505648.html