C++远征计划的学习者确定是冲着封装,继承,多态来的。ios
知识点:c++
#define VS const(更强数据控制力)
引用类型:程序员
引用就是变量的别名数组
只有别名,别名就变成了真实姓名.只有别名也是没法进行命名的。函数
#include <stdlib.h> #include <iostream> using namespace std; int main(void) { int a = 3; // 给a起了一个别名b int &b = a; //引用必须初始化 b = 10; // 给b赋值10,a的值也就由3变为10 cout << a << endl; system("pause"); return 0; }
为a起别名b: 对别名作的操做就是对a自己作了操做[叫小萝卜头干什么,罗某某也干了什么]学习
使用别名对于结构体作操做的例子:spa
typedef struct { int x; int y; }Coor;
#include <stdlib.h> #include <iostream> using namespace std; typedef struct { int x; int y; }Coor; int main(void) { Coor c1; Coor &c = c1; // 给c1起了别名c c.x = 10; // 使用别名对真实值作操做 c.y = 20; cout << c1.x << endl << c1.y << endl; system("pause"); return 0; }
类型 *&指针引用名 = 指针;
#include <iostream> using namespace std; int main(void) { int a = 10; int *p = &a; // 定义指针p int *&q = p; // 指针p的别名q *q = 20; cout << a << endl; system("pause"); return 0; }
int a = 10;
// 给a分配一个内存逻辑地址,如0x100001。这个地址存放了值10;int *p = &a;
//建立指针变量p指向a,给p分配地址0x100002,这个地址存放的值是"0x100001"(a的逻辑地址值);int *&q = p;
// (给指针p起别名q)建立变量q,给q分配地址也是0x100002, 所以这个地址存放的值仍是a的逻辑地址值;*q = 20;
// (对q作操做)访问存放在q变量地址下的值,得到了a的地址值, 再访问一下a的地址值,修改里面存放的内容为20;C语言中将两个数的值进行交换:操作系统
void fun(int *a, int *b) { int c =0; c =*a; *a =*b; *b =c; } int main() { int x =10; int y =20; fun(&x,&y); return 0; }
c++中引用实现:3d
void fun(int &a, int &b) { int c =0; c =a; a =b; b =c; } int main() { int x=10,y=20; fun(x,y) return 0; }
a是x的别名。b是y的别名。 里面操做的就是实际的参数了。指针
基本数据类型引用示例:
2-2-C++Two-ReferenceDemo/main.cpp
#include <iostream> #include <stdlib.h> using namespace std; int main(void) { int a = 10; int &b = a; // 定义一个引用(别名) // int &b = NULL; 计算机会报错, 初始化 没法从 int 转换为 int & b = 20; cout << a << endl; a = 30; cout << b << endl; system("pause"); return 0; }
对于本体和别名的操做具备相同的效果。
结构体引用示例:
2-2-2-C++Two-ReferenceStructDemo/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; typedef struct { int x; int y; }Coord; //Coord 坐标 int main(void) { Coord c; Coord &c1 = c; // 起别名c1 c1.x = 10; c1.y = 20; cout << c.x << endl << c.y << endl; system("pause"); return 0; }
指针引用示例:
2-2-3-C++Two-ReferencePointerDemo/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; int main(void) { int a = 3; int *p = &a; int *&q = p; // 指针p的别名q *q = 5; cout << a << endl; system("pause"); return 0; }
函数参数引用示例:
2-2-4-C++Two-ReferenceFunctionParameter/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; void fun(int &a, int &b); int main(void) { int x = 10; int y = 20; cout << x << endl; cout << y << endl; fun(x, y); cout << "交换后:" << endl; cout << x << endl; cout << y << endl; system("pause"); return 0; } void fun(int &a, int &b) { int c = 0; c = a; a = b; b = c; }
看起来传入的是实参x,y 实际上 a是x的引用,b是y的引用
int a; int &b = a; int &c = a;
一个本体能够起多个别名
定义一个引用y,y是x的引用,而后打印x和y的值。将y的值更改以后再次打印,x和y的值。
2-2-5-C++Two-ReferenceUnitDemo/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; int main(void) { int x = 3; //定义引用,y是x的引用 int &y = x; //打印x和y的值 cout << x << endl; cout << y << endl; //修改y的值 y = 5; //再次打印x和y的值 cout << "After Change Y:" << endl; cout << x << "," << y << endl; system("pause"); return 0; }
const关键字是用来控制变量是否能够变化的。
没有const以前的状况:
int x =3; //变量
const int x=3; //此时的x为常量
x变成了一个常量,没法进行更改。再赋值其余数字,编译时就会报错。
const int *p=NULL;
彻底等价于int const *p=NULL
int *const p=NULL
与前两种有区别。
const int * const p = NULL;
彻底等价于 int const * const p = NULL;
int x =3; const int *p = &x; // p = &y;正确 // *p = 4;错误
const 修饰
*p
; 所以p能够指向其余的地址,但*P
不能够被改变。
变量名 | 存储地址 | 存储内容 |
---|---|---|
x | &x | 3 |
p | &p | &x |
int x =3; int *const p = &x; // p = &y;错误 // *p = 4;正确
const写在了
*
的后面。const 修饰p; const修饰的p只能指向一个地址。
变量名 | 存储地址 | 存储内容 |
---|---|---|
x | &x | 3 |
p | &p | &x (不可改变) |
const 修饰p;
const int x =3; const int *const p = &x; // p = &y; 错误 // *p = 4; 错误
变量名 | 存储地址 | 存储内容 |
---|---|---|
x | &x | 3 (不可改变) |
p | &p | &x (不可改变) |
int x =3; const int &y =x; // x=10; 正确 // y=20; 错误 y做为别名加了const
变量名 | 存储地址 | 存储内容 |
---|---|---|
x | &x | 3 |
//错误 const int x =3; x =5; // 常量x不能进行赋值了 //错误 int x =3; const int y =x ; y = 5; // y 变成了常量,不能再赋值 //错误 int x =3; const int *y =&x; // 修饰*y *y = 5; // *y不可变化 //错误 int x =3,z=4; int * const y = &x; y = &z; // 修饰y 不容许从新指向 //错误 const int x =3; const int &y =x; y =5; //错误:指针会存在改变常量的风险。 const int x =3; int *y = &x; // x不可变,指针可变。 // 使用一个可变的指针,指向一个不可变的变量。风险是能够经过*y的方式改变x的值。 // 编译器会禁止 //正确。x拥有读写,y只可读。 int x =3; const int *y =&x; //权限小的接收权限大的
3-2-1-constIntChangeDemo/main.cpp
#include "stdafx.h" #include <iostream> using namespace std; int main(void) { const int x = 3; x = 5; system("pause"); return 0; }
1> error C3892: “x”: 不能给常量赋值
经过define和const修饰的均可以达成设置常量目的。
3-2-2-constPointerChangeDemo/main.cpp
#include <iostream> using namespace std; int main(void) { int x = 3; int y = 4; int const *p = &x; // const int *p = &x等价 // 都是修饰*p的 //*p = 5; x = 5; p = &y; cout << *p << endl; system("pause"); return 0; }
此时*p
的值不能进行修改。可是能够修改p指针指向的地址
错误 C3892 “p”: 不能给常量赋值
3-2-3-constPointerChangeDemo2/main.cpp
#include <iostream> using namespace std; int main(void) { int x = 3; int y = 5; int *const p = &x; // const修饰p // p = &y; // p不能给常量赋值 *p = 10; cout << x << endl; system("pause"); return 0; }
此时对于p指向的地址不能修改。可是对于
*p
的值能够进行修改。
3-2-4-constPointerMoveDemo/main.cpp
#include <iostream> using namespace std; int main(void) { int x = 3; int y = 5; int const *p = &x; cout << *p << endl; p = &y; //*p = 10; cout << *p << endl; system("pause"); return 0; }
由于此时const修饰的*p
,而p是能够移动到其余地址。
const修饰一个引用:
3-2-5-constReferenceDemo/main.cpp
#include <iostream> using namespace std; int main(void) { int x = 3; int y = 5; int const &z = x; // z = 10; // z不能被改变 x = 20; cout << x << endl; system("pause"); return 0; }
别名被限制上了不能修改,可是原变量是能够修改的。
函数中的const
由于能够保证传入函数内部的值不会由于误操做而修改原有值
3-2-6-constFunctionDemo/main.cpp
#include <iostream> using namespace std; void fun( const int &a, const int &b); int main(void) { int x = 3; int y = 5; fun(x, y); cout << x << "," << y << endl; system("pause"); return 0; } void fun( const int & a, const int & b) { // 错误由于传入的值为const。不能进行修改。 a = 10; b = 20; }
把const去掉,由于传入的是引用,因此原始值能够被修改。
而当const修饰以后,传入函数内部的值并不会修改原有值
关于const用法,如下错误的是:
A. int const a = 3; int *p = &a; // B. int a = 3; int const *p = &a; C. int a = 3; int * const p = &a; D. const int a = 3; int const &b = a;
B const 修饰
*p
C const 修饰p
D const修饰a的别名b
mtianyan:指针指向const修饰的变量时,应该是const int const *p = &a;
使用const关键字定义整型变量count,并定义指针p引用变量count。利用for循环打印count次Hello C++
3-4-C++-UnitDemo/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; int main(void) { // 定义常量count const int count = 3; int const *p = &count; // 打印count次字符串Hello C++ for (int i = 0; i < *p; i++) { cout << "Hello C++" << endl; } system("pause"); return 0; }
由于只对*p
进行了const。所以可让p指向其余地址。
void fun(int i, int j=5, int k=10); // j,k有默认值 void fun(int i, int j=6, int k); // 错误写法
有默认参数值的参数必须在参数表的最右端
声明写默认值,定义不建议写。 定义时写默认值有些编译器没法经过。
void fun(int i, int j = 5, int k = 10); void fun(int i, int j, int k) { cout << i << j << k; }
使用时:
int main() { fun(20); fun(20,30); fun(20,30,40); }
无实参则用默认值,不然实参覆盖默认值
前提: 在相同做用域下
两个条件:
demo代码:
int getMax(int x, int y, int z) { //TO DO } double getMax(double x ,double y) { //TO DO }
思考:编译器如何识别重载的函数
实际的编译以后,名称+参数造成新的函数。来区分两个所谓的同名函数。
int getMax(int x, int y, int z)
->getMax_int_int_int
double getMax(double x ,double y)
->getMax_double_double
调用时,则根据实参类型和个数自动识别。
重载的好处:
主调函数调用普通函数有五个步骤:
- 调用fun(),2. 找到fun()的相关函数入口 3. 执行fun() 中的相关代码 4. 返回主调函数
内联函数会在编译时将函数体代码和实参代替函数调用语句。
内联函数关键字inline
inline int max(int a,int b,int c); int main() { int i =10,j=20,k=30,m; m = max(i,j,k); cout<<"max="<<m<<endl; return 0; }
使用时和普通函数同样使用。代码展开后至关于代码粘贴进来。
思考: 为何不全部地方都使用内联函数?
学习函数默认参数,重载,内联函数。
4-2-c++-functionDefaultParameter/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; void fun(int i=30, int j = 20, int k = 10); int main(void) { fun(); fun(100); fun(100, 200); fun(100, 200, 300); system("pause"); return 0; } void fun(int i, int j, int k) { cout << i << "," << j << "," << k << endl; }
已传入的实参覆盖默认值,未传入的使用默认值。 默认值从右侧开始赋值,声明时赋默认值,定义时不要默认值。
前提条件,函数在同一个做用域下,默认多个函数在同一个命名空间时。
当没有定义命名空间时,函数同名就默认是重载了。
4-2-C++-FunctionOverload/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; void fun(int i = 30, int j = 20, int k = 10); void fun(double i = 30.0, double j = 40.0); int main(void) { // fun(); //“fun” : 对重载函数的调用不明确 // 有多个 重载函数 "fun" 实例与参数列表匹配 fun(1, 2); fun(1.1, 2.2); system("pause"); return 0; } void fun(int i, int j, int k) { cout << i << "," << j << "," << k << endl; } void fun(double i, double j) { cout << i << "," << j << endl; }
fun() 两个函数均可以,所以编译器懵了。
inline函数实现只须要加上inline关键字
inline void fun(int i = 30, int j = 20, int k = 10); inline void fun(double i = 30.0, double j = 40.0);
inline这种内联,只是一种编译方式,结果上没有什么不一样。
C++的重载的两个函数参数数量能够相同也能够不一样, 当参数数量相同时,只须要对应参数类型不一样即称为重载。
4-4-ReturnMaxDemo/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; /** *函数功能:返回a和b的最大值 *a和b是两个整数 */ int getMax(int a, int b) { return a > b ? a : b; } /** * 函数功能:返回数组中的最大值 * arr:整型数组 * count:数组长度 * 该函数是对上面函数的重载 */ int getMax(int arr[], int count) { //定义一个变量并获取数组的第一个元素 int a = arr[0]; for (int i = 1; i < count; i++) { //比较变量与下一个元素的大小 if (a <arr[i]) { //若是数组中的元素比maxNum大,则获取数组中的值 a = arr[i]; } } return a; } int main(void) { //定义int数组并初始化 int numArr[3] = { 3, 8, 6 }; //自动调用int getMax(int a, int b) cout << getMax(6, 4) << endl; //自动调用返回数组中最大值的函数返回数组中的最大值 cout << getMax(numArr, 3) << endl; system("pause"); return 0; }
什么是内存管理?
思考:内存的本质是什么?
内存的本质是一种资源,由操做系统掌控。
咱们能作什么?
咱们能够对内存进行申请和归还操做,申请/归还内存资源称为内存管理。
运算符: new
delete
int *p=new int;
delete p;
这是申请和释放某一个内存
int *arr=new int[10]; // 申请块内存 delete []arr; // 释放快内存
内存操做注意事项
回忆: 申请和释放内存的其余方式
void *malloc(size_t size); // 使用申请内存函数 void free(void *menblock); // 使用释放内存函数
new
delete
运算符配套使用不要混搭
int *p=new int [1000]; if(NULL==p) { //内存分配失败 }
释放内存注意:
int *p=new int [1000]; if(NULL==p) { //内存分配失败 } delete []p; p = NULL; int *p=new int; if(NULL==p) { //内存分配失败 } delete p; p = NULL;
不置为空,它就会指向刚才那块内存。咱们若是再次使用delete,就会形成同一块内存回收两次。
计算机会出现异常。
使用new
申请内存,使用delete
释放内存,配套使用。
申请内存须要判断是否失败。释放内存要记得指针置空。
new和delete配套使用
5-2-NewDeleteMemoryManage/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; int main(void) { //int *p = new int(20); //申请同时初始化 int *p = new int; if (NULL == p) { system("pause"); return 0; } *p = 20; cout << *p << endl; delete p; p = NULL; system("pause"); return 0; }
申请块内存:
5-2-2-BlockMemoryManage/main.cpp
#include <stdlib.h> #include <iostream> using namespace std; int main(void) { int *p = new int[1000]; if (NULL == p) { system("pause"); return 0; } p[0] = 10; p[1] = 20; cout << p[0] << "," << p[1] << endl; delete []p; // 注意这里的[],不然只会释放第一块。 p = NULL; system("pause"); return 0; }
在堆中申请100个char类型的内存,拷贝Hello C++字符串到分配的堆中的内存中,打印字符串,最后释放内存。
5-4-StrcpyMemoryMange/main.cpp
#include <string.h> #include <iostream> using namespace std; int main(void) { //在堆中申请100个char类型的内存 char *str = new char[100]; if (NULL == str) { system("pause"); return 0; } //拷贝Hello C++字符串到分配的堆中的内存中 strcpy_s(str,100,"Hello C++"); //打印字符串 cout << str << endl; //释放内存 delete[]str; str = NULL; system("pause"); return 0; }
没有与参数列表匹配的 重载函数 "strcpy_s",添加char数组的长度。