1.命名空间
(1).概念
C语言是将库函数封装在头文件中,我们在对变量等命名的时候不能和库函数的一样,例如printf。所以C++中为了避免这个问题,引入命名空间的概念,即:某个命名仅仅在它的命名空间起作用,通过这个很好的将同名问题解决了。
(2).命名空间的定义
namespace N
{
//变量
int a =10;
//函数
}
1.直接定义
2.可以嵌套
3.同一工程下同名命名空间会合并。
(3).命名空间的使用
1.通过作用域限定符 ::
N::a声明a是属于N这个命名空间的
2.使用using将命名空间的变量引入
using a
3.使用using namespace 将命名空间引入
using namespace std
将std库打开,那么这个就会退化为C中的用法。不能定义同名,但是使用方便,不用限定范围。
2.缺省参数
(1).概念
缺省参数是声明或者定义函数时为参数指定一个默认值,如果没有指定实参,就使用缺省的参数值,如果指定实参,那么缺省参数不生效。
void TestFunc(int a = 0) {
cout<<a<<endl; }
int main()
{
TestFunc(); // 没有传参时,使用参数的默认值
TestFunc(10); // 传参时,使用指定的实参
}
(2).缺省分类
全缺省
void TestFunc(int a = 10, int b = 20, int c = 30) {
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl; }
半缺省
void TestFunc(int a, int b = 10, int c = 20) {
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl; }
半缺省只能从右向左缺省。
定义和声明不能同时出现缺省值,因为可能造成编译器无法确定使用哪一个值。
3.重载
(1)概念
重载是函数使用的特殊情况,也就是使用同名函数。
这个在C语言中是不支持同名函数的,因为在最后链接时,是通过符号表去找相应的函数地址,C语言是通过函数名去找地址,所以同名函数会造成编译器不知道调用哪个函数。
在C++中,符号表存储函数的时候是Z+函数名字母个数+类型。
例如Add(int a,int b) --> Z3Addii
这样就可以将同名函数区分出来,实现重载。
需要注意的是,重载必须是同名函数,参数的类型或者个数,或者顺序,任意一个不同才可以。通俗的说,就是让它们在链接器链接的时候能区分调用的函数。所以void add(int a,int b)和void add(int b,int a)不能发生重载,因为它们的命名都是Z3addii。
(2)程序运行的几个阶段
这里来回忆一下程序运行的几个阶段
预处理:头文件展开,宏替换,去注释,条件编译等
编译:检查语法错误,生成汇编代码。
汇编:将汇编代码转化为二进制指令
链接:将几个目标文件链接起来,形成可执行的文件。
4.引用
(1).概念
引用就是别名,实现的作用就是对原来地址空间的数据进行操作,和指针差不多,底层实现依靠指针,以交换数值为例子。
(2).区别
和指针的区别,通过指针的话,需要新开辟两个临时空间储存地址,然后通过地址完成交换,最后释放地址空间。
和直接交换的区别,我们如果直接在main函数里面完成交换,和引用就一样了。如果通过调用函数来完成,那么新开了空间直接存数据,改变这个地址下面的数据,对原有的空间数据没有影响,是不能完成交换的。
有多级指针,没有多级引用。
指针需要解引用,引用编译器自己处理。
引用始终和原有类型相同,而指针是地址空间占用的字节大小。
引用比指针更安全。
(3).特性
1.引用必须初始化,而指针不需要初始化。
2.引用类型和引用实体必须是同类型的,但是不同类型的引用,例如最后一个,这里是新开了一个空间将d的值存储起来,然后在引用这个区域。所以这个空间的值是不可以改变的。这里要用const来实现引用的权限限制。
3.引用一旦引用一个实体,就不能引用其他实体。
4.引用时权限可以缩小,但是不能放大。
void TestConstRef()
{
const int a = 10;
//int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
// int& b = 10; // 该语句编译时会出错,b为常量
const int& b = 10;
double d = 12.34;
//int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
}
(4).应用场景
1.做参数
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
2.做返回值
int& Count()
{
static int n = 0;
n++;
// ...
return n;
}
注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
5.内联函数
(1).概念
以inline修饰的函数叫做内联函数,调用内联函数,直接展开,减少压栈的开销,提升了运行效率。但是内联函数必须是相对简单的代码,本质上是一种以空间换时间的做法。
(2).和宏的区别
宏
优点:代码可以复用,提高性能
缺点:没有类型安全检查
不方便调试,在预处理就被替换了
代码可读性差
C++中 常量定义 使用const修饰
函数定义使用内联函数。
inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
6.extern “c”
在C++编译过程中,有的函数需要以C的风格编译,我们通过声明,告诉编译器,这里使用C语言的语法编译。在符号表的命名就会以C语言的方式去命名。
7.auto
(1).概念
auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得,由后面的类型直接推导出前面变量的类型。
(2).注意事项
1.使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。
2.用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
3.auto不能作为函数的参数
4.auto不能用来声明数组
5.使用auto时,同一行的类型必须相同。
8.NULL和nullptr
NULL实际上是一个宏。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下
将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。
为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr
9.for
for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,比原来写法简洁了许多。
void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
e *= 2;
for(auto e : array)
cout << e << " ";
return 0;
}
注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。
初学C++,担心自己猴子搬玉米,所以写一点笔记,如果有错误,欢迎留言指导,一起进步!!!