一:匿名命名空间的又一特点://匿名命名空间等同于全局变量,匿名命名空间会和全局变量发生冲突
namespace //没有名字,叫匿名命名空间,可以访问num吗?
{
int num=100;
}
//int num = 300; 错误
void main()
{
num=200;
cout << num << endl;
cin.get();
}
第九课
1:命名空间的深入
没有使用命名空间
/*标准命名空间的2种方法,第一种:如果有using,可以省略命名空间,
第二种,如果没有using,必须制定命名空间,可是一些公司禁止使用using namespace std;
因为你在这里就明确了那个空间了*/
void main()
{
std::cout << "hello"<< std::endl;
std::cin.get();
}
2:可以把命名空间起些别名,自定义,给自定义的起个别名
/用bobo代表std可以吗?标准的在这里不可以替代,自定义的可以替代,下面举例,可以的
namespace stdrun//创建一个namespace stdrun
{
int num = 20;
void show()
{
std::cout << num << std::endl;
}
}
namespace bobo = stdrun;//给自定义的起个别名
namespace doubo = std;//给标准的起别名,一般不建议用
void main()
{
bobo::show();
std::cin.get();
}
3:了解关键字using
using也有作用域,它的作用域等同于局部变量,可以放在任何位置,但是前面要加上std::
下面的是错误的
void run()
{
using namespace std;//using也有作用域,它的作用域等同于局部变量
cout << "helloworld"<< endl;
}
void main()
{
cout << "hello";
std::cin.get();
}
第10课:cpp全局变量和using
C语言里面的全局变量是声明和定义,cpp
1:下面这个例子在C语言里面没事,在cpp里面可不行,发生重名现象
#include<stdlib.h>
int a;
int a;
void main()
{
system("pause");
}
2:#include<iostream>
//#include<cstdlib.h>
//下面这个举例是int a 重定义了,cpp没有生命和定义的差别,只有定义,是从命名空间来开启
using namespace std;
int a;
//匿名空间,原则上匿名的命名空间能不使用最好不使用
using namespace
{
::a = 3;//双冒号作用是引用全局
}
void main()
{
::a = 6;//引用全局,不包含匿名
cin.get();
}
3:关于using的一些深入细节
using和全局变量会发生冲突问题,下面举例:
举例1:#include<iostream>
using namespace std;
int num = 10;
namespace data
{
int num = 100;
}
void main()
{
cout << num << endl;//结果是10,
cin.get();
}
举例2:有了:using namespace data;num是不确定的值,有2种情况,
#include<iostream>
using namespace std;
int num = 10;
namespace data
{
int num = 100;
}
void main()
{
using namespace data;
cout << ::num << endl;//结果是10
cout<<data::num<<endl;//结果是100
cin.get();
}
4:using和局部变量会发生冲突问题,下面举例:值是5,这中间会发生一现象,覆盖。
作用域生效的局部变量会覆盖命名空间
namespace data
{
int numx = 10;
}
void main()
{
int numx = 5;
using namespace data;
cout << numx << endl;//结果是10,
cin.get();
}
5:cpp的全局变量和局部变量会有什么特点呢?从下面这个例子区分全局和局部
int num = 100;
void main()
{
int num = 200;
cout << num << endl;//结果是200,
cout << ::num << endl;//结果是100,
cin.get();
}
此时此刻num是多少,看下面例子:双冒号始终代表最全局,并不是跳过块语句,局部变量会覆盖
int num = 100;
void main()
{
int num = 200;
{
int num = 300;
cout << num << endl;//结果是300,
cout << ::num << endl;//结果是100,双冒号始终代表最全局,并不是跳过块语句,局部变量会覆盖
}
cin.get();
}
第11课
命名空间瀑布,瀑布模型没有听懂
//一般情况,函数放在命名空间外,命名空间内部放置声明
namespace data//自定义data数据类型的封装
{
}
int data::add(int a,int b)//data属于命名空间
{
return a + b;
}
第12课:类型与命名空间
1:类与命名空间
//cpp的结构体里面可以有函数,其实struc在这里面就是一个类,类的特点是把数据和函数都放在一起
struct data
{
int a;
int b;
int getadd()
{
return a + b;
}
};
void main()
{
data data1;//访问变量,调用方法
data1.a = 10;
data1.b = 20;
cout << data1.getadd() << endl;
cin.get();
}
2:如果这个类在命名空间里面,直接使用data换行不?答案是有std,std的作用是拓展标准命名空间,如果不是std
namespace std //
{
struct data
{
int a;
int b;
int getadd()
{
return a + b;
}
};
}
void main()
{
data data1;//访问变量,调用方法
data1.a = 10;
data1.b = 20;
cout << data1.getadd() << endl;
cin.get();
}
3:数据类型可以放在命名空间里,避免数据类型重名
下面举例:
namespace stdfun//需要声明一下命名空间,再确认一下它是什么类型
{
struct data
{
int a;
int b;
int getadd()
{
return a + b;
}
};
}
void main()
{
stdfun::data data1;//访问变量,调用方法
data1.a = 10;
data1.b = 20;
cout << data1.getadd() << endl;
cin.get();
}
第13课 匿名命名空间和stack产生的冲突问题 :不懂
static和extern在cpp场合的一些运用
//匿名命名空间和extern发生冲突,如果访问x,加双冒号::
extern int x;//引用外部全局变量
namespace
{
int x = 999;
}
void main()
{
cout << ::x <<endl;
cin.get();
}
//static int x = 12;
int x = 10;//static作用于当前文件
static int x1 = 100;//加static 是当前文件访问
namespace
{
static int x1 = 999;
}
void main()
{
cout << ::x1 <<endl;//加双冒号大家想是引用静态还是全局呢?
cin.get();
}
第14课
typeid作用是获取这个类型, type 类型, id编号
cpp作为强类型的编程语言,自然而然会具备功能:动态获取数据类型
typeid和int一样,蓝色,是关键字,不是函数
//typeid的作用是获取数据类型,获取后可以进行判断
void main()
{
int a;//我们怎么显示a的类型呢?
cout << typeid(a).name() <<endl;//加双冒号大家想是引用静态还是全局呢?
cout << typeid(10).name() << endl;//也是int 类型
cout << typeid(12.3).name() << endl;//double类型
cout << typeid(10 + 0.6).name() << endl;
cout << typeid('A').name() << endl;
cout << typeid("helloworld").name() << endl;//char const [11]检测出是一个数组,就是const类型
//判断下面类型相等吗?cpp作为强类型变成语言,可以判断出来,其实涉及到动态的数据类型
int *px;
int *py;//int *px; char *py; 结果是!=
if (strcmp(typeid(px).name(),typeid(py).name())==0)
{
cout << "==";
}
else{
cout << "!=";
}
cin.get();
}
第15课 可变函数头文件cpp里面的 #include<cstdarg>
挑战复杂的,cpp里面经常会遇到类型不确定,个数也不确定的函数模板怎么写?
可变参数函数模板 举例,先看下类型一致的情况
(1)简单的类型一致情况下。处理多个参数,参数类型一致
//c语言的可变函数#include<stdarg.h>,cpp语言的可变函数#include<cstdarg>
//模板的可变参数,实现了3个可用的函数模板,记住几个重要的,va_list代表一个指针,va_start代表开始,va_end代表结束,arg代表取一个数据,T代表不确定的数据类型
template<class T>
T add(int n,T t...)//实现把n个数相加,若是可变参数,要带3个点,带3个点,意味着可变参数。第一个代表多少个参数,第二个代表多少个类型的列表
{
cout << typeid(T).name() << endl;//打印类型
va_list arg_ptr;//代表开头指针
va_start(arg_ptr, n);//从那个数开始呢?我们调用一个宏,va_start,从n个数开始读取。从arg_ptr开始读取N个数
T res(0);//需要结果,创建一变量,初始化为0
for (int i = 0; i < n;i++)//读取
{
res+=va_arg(arg_ptr,T);//根据数据类型取出数据
}
va_end(arg_ptr);//结束读取,需要一个宏。va_end
cout << res << endl;//打印值,实现泛型操作
return res;
}
void main()
{
cout << add(4,1,2,3,4) << endl;
cout << add(5,1,2,3,4,5) << endl;
cout << add(5, 11.3, 2.2, 3.6, 4.1, 5.2) << endl;
cin.get();
}
(2)类型不一致情况,处理多个参数,参数类型不一致,个数不确定的情况下:
//typename和class效果一样,都代表类型,typename...cpp的宏定义,代表可变参数的类型
void show()//作用是结束递归
{
}
//需要用到2个,typename比class作用域更强, typename...Args作用是处理可变参数,任何类型都可以解决
template<typename T, typename...Args>
void show(T t, Args...args)
{
cout << t << endl;//打印
show(args...);//递归,递归要有一结束的,上面有一空函数,show();
}
void main()
{
show(1,1.1,"123",'A');
cin.get();
}
(3)//面试问题:请给我用函数参数,可变参数模板给我实现一个printf或者给我实现一个scanf,用cpp实现它
举例:实现printf,考你2个点:对cpp类型的了解,对cpp字符串的了解
//用可变参数来实现它
void show(const char *str)//作用是结束递归
{
cout << str;
}
第18课
//需要用到2个,typename比class作用域更强, typename...Args作用是处理可变参数,任何类型都可以解决
template<typename T, typename...Args>
void show(const char *str,T t, Args...args)
{
while (str && *str)//指针不为空且字符串没有到末尾
{
if (*str=='%' && *(str+1)!='%')
{
++str;//指针向前移动
cout << t;//打印
show(++str,args...);
return;
}
else{
cout << *str++;//等价于跳过一个字符
}
}
}
void main()
{
printf("%dABCDEFG%s%c%%%fXXXX",10,"1234",'0',1234.5);
putchar('\n');
show("%dABCDEFG%s%c%%%fXXXX", 10, "1234", '0', 1234.5);
cin.get();
}
第18课
//外观模式 默认参数赋值,不需要设置,先跑起来再说
//外观模式优点:让函数可以快速调用,省略参数,默认参数都从右边开始,不默认的参数放在左边,参数进栈的顺序从右向左
int add(int a, int b, int c = 1,int d=1)
{
return a + b + c+d;
}
void run(char * str="notepad")//属于外观模式一种
{
system(str);
}
void main()
{
cout << add(1,2) << endl;
cout << add(1, 2,3) << endl;
cout << add(1, 2,3,4) << endl;
//run();
cin.get();
}
第19课 auto
(1)auto在c语言里面
/*
c语言里的auto代表自动变量,和cpp的auto是天壤之别,在c里面成立
*/
void main()
{
auto int num;//创建一变量在栈上。在c上面成立,在cpp上不成立,在cpp改的是面目全非,auto是自动变量,在栈上的特点是是自动分配,自动释放
cin.get();
}
(2)auto在c++语言里面,auto用法一 //auto double num = 3 + 1.2;错误,auto不能和任何数据类型组合,c可以
/*
cpp语言里的auto是自适应数据类型,自动推理,自动把类型推理出来。
*/
void main()
{
//获取一个数据类型用typeid,下面的auto是什么 数据类型?
//auto int num;//创建一变量在栈上。在c上面成立,在cpp上不成立,在cpp改的是面目全非,auto是自动变量,在栈上的特点是是自动分配,自动释放
//auto num = 10;//属于int数据类型
//auto num = 10.3;//属于double数据类型
//auto num = L'bobo';
//auto num = 3 + 1.2;//属于double类型
//auto double num = 3 + 1.2;错误,auto不能和任何数据类型组合
auto num = 3 / 5;//int类型,整数和整数除的结果一定是整数。int
cout << typeid(num).name() << endl;
cin.get();
}
(3)auto特点:举例下面
/*
cpp语言里的auto是改变原本
*/
void main()
{
int a[5] = {1,2,3,4,5};
//如何写一个表达式把它循环表达出来
/*for (auto i:a)//这个auto i属于副本
{
i += 1;
cout << i << endl;
}*/
for (auto & i:a)//auto i是副本,auto &是原本,&是引用
{
i += 1;
cout << i << endl;
}
for (auto i:a)//这个auto i属于原本
{
cout << i << endl;
}
cin.get();
}
(4)auto在模板里面实现加法。实现了auto的绝对值精准
template<class T1,class T2>//不需要分号
/*T1 add(T1 t1,T2 t2)
{
return t1 + t2;
}*/
auto add(T1 t1,T2 t2)//实现了auto的绝对值精准,auto在这的作用是自动推理数据类型
{
return t1 + t2;
}
void main()
{
cout << add(10,11.9) << endl;//结果是21,不能保证结果的精确,确保结果精准,用auto,把T1或者T2换成auto
cin.get();
}
第20课 bool 以0和1为基准 bool赋值情况只有2种情况 0或1
(1)举例
void main()
{
//大家认为会打印那个值啊
bool boer = 6;//非0解析为1,0解析为0
cout << boer << endl;//结果是1
bool boer = -6;
cout << boer << endl;//结果是1
bool boer = 0;
cout << boer << endl;//结果是0
cout << sizeof(boer) << endl;//结果是1个字节
//在c和cpp里面赋值2个关键字 ture false
bool boer = true;//非0解析为1,0解析为0
cout << boer << endl;//结果是1
cin.get();
}
(2)举例 bool数据类型初始化哪几种形式呢
void main()
{
bool bore1(false);
bool bore1(true);
//对bore1进行赋值
bore1 = 0 && 10 && -1 || 2 + 3;//优先级+在前。结果是0||2,为死循环
while (bore1)
{
cout << "波尔回事死循环吗";
}
cin.get();
}
第21课 decltype 如果你改过游戏,都知道decltype 没有听懂
void main()
{
//auto初始化,打印它的值和类型
auto bore("hello world"); ()只能用于初始化
auto afu(1 && 0 && 3|| -1);
cout << typeid(afu).name() << " " << afu << endl;
cin.get();
}
第22课 c,cpp数组初始化细节
(1)c,cpp数组区别 ,以后尽量少用c风格数组,多用cpp风格数组
cpp第一种方式:int a[5]{1,2,3,4,5};
for (auto i:a)//遍历
{
cout << i << endl;
}
(2) cpp 第二种方式 auto在这里只能用于数组不能用于指针指向一个数组,new可以指定它在堆上分配,可以指定它在栈上分配,可以指定它在静态分配,所以new的功能强大
在cpp里面数组初始化的2种方法:
int a[5]{1,2,3,4,5};
int *p(new int[5]{1,2,3,4,5});
// int *p(new int[5]{1, 2, 3, 4, 5});//创建一指针对它进行分配内存并且初始化,new在这里等价于c语言里的malloc。,z只能用new来分配
void main()
{
int *p2(new int[5]{1,2,3,4,5}); cpp的真正写法,这数组在堆上,在cpp里面
for (int i = 0; i < 5;i++)//遍历
{
cout << p2[i] << endl;
}
cin.get();
}
(3)在c里面的数组
int *p=(int[20]{[4]=1,[5]=2});//赋值
for (int i = 0; i < 5;i++)
{
printf("\n%d",p[i]);
}
第23课 cpp风格数组 什么是cpp风格数组?以后禁止使用int a[5],int a[10]这样的数组,要使用cpp风格的数组
头文件#include<array> 我们用到了数组
介绍一下c风格的数组,cpp风格的数组
(1)c风格的数组
int a[3]{ 1, 2, 6 };
int b[5][5] = { 0 };//无法用auto循环,因为它不是cpp风格数组
(2)cpp风格的一维数组
//第一个参数类型,第二个参数是个数,创建一个myint这样的数组
array<int,10>myint{1,2,3,4,5,6,7,8,9,10};//纯粹的cpp风格的数组
//显示数据
for (auto i:myint)
{
cout << i <<" "<<(void*)&i<< endl;//地址是一样的,因为i有副本机制,不能用这种方式查看地址
}
//在内存里面查看地址 ,这个结果才是在内存里面是连续的。
for (int i = 0; i < 10;i++)
{
cout << myint[i] << " " << (void*)&myint[i]<< endl;//地址是一样的,因为i有副本机制,不能用这种方式查看地址
}
//怎么判断是在堆上或者栈上
array<int, 100000>myint{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//出现stack overflow;是栈溢出,说明在栈上
cin.get();
(3)cpp风格的二维数组怎么写,以后写矩阵都要用这个方式,但凡游戏,用cpp风格数组,2为数组,3为数组等,稳定性好
我是一个数组,我的每个元素又是一个数组
//第一个参数类型,第二个参数是个数,创建一个myint这样的数组
array<int,10>myint1{11,2,3,4,5,6,7,8,9,10};//纯粹的cpp风格的数组
array<int,10>myint2{21, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
array<int, 10>myint3{ 31, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
array<array<int, 10>, 3>myint{myint1,myint2,myint3};
for (auto j:myint)
{
for (auto i:j)
{
cout << i << " ";
}
cout << "\n";
}
双for循环
array<int,10>myint1{11,2,3,4,5,6,7,8,9,10};//纯粹的cpp风格的数组
array<int,10>myint2{21, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
array<int, 10>myint3{ 31, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
array<array<int, 10>, 3>myint{myint1,myint2,myint3};
for (int i = 0; i < 3;i++)
{
for (int j = 0; j < 10;j++)
{
cout <<" "<<myint[i][j];
}
cout << endl;
}
(4)写三维数组,在套,好比中国有好多个省,每个省里有市,每个市里有县,等 一层一层的调,把数组赋给数组,没有写
第24课 nullptr null c风格空指针 nullptr cpp风格空指针,区别在于默认类型的不一样,NULL会把它当作一空类型,nullptr被当作cpp默认的空指针类型,用ptr是严格类型的匹配
举例:
//他们之间为什么没有发生冲突呢?因为重载
void show(int num)
{
cout << "int类型"<< endl;
}
void show(int *p)
{
cout << "int *类型" << endl;
}
void main()
{
/*show(NULL);//如果传递null,大家觉得调用哪个值,调用int类型,
因为null会把它解释为一个整数为0,但是cpp里面保证类型的严格,应该用nullptr*/
show(nullptr);//会显示int *类型
//打印他们的类型
cout << typeid(NULL).name() << endl;
cout << typeid(nullptr).name() << endl;
cin.get();
}
第25课 cpp风格别名