目录
1. C++关键字
2. 命名空间
1.命名空间定义
2.命名空间使用
1.加命名空间名称及作用域限定符
2.使用using将命名空间中成员引入
3.使用using namespace 命名空间名称引入
3. C++输入&输出
4. 缺省参数
5.函数重载
1.什么是函数重载
2.extern “C
6.引用
1.概念
2.引用特性
1.一个变量可以有多个引用
2.引用在定义时要初始化
3.引用一旦引用一个实体,再不能引用其他实体
3.常引用
1.引用后变量的权限只能缩小,不能够放大
4.使用的场景
1.做函数的参数
2.做函数的返回值
5.传值、传引用效率比较,及二者区别
7.内联函数
8.auto关键字(C++11)
1.概念,用法
2.auto不能推导的场景
3.基于范围的for循环(C++11)
1. 范围for的语法
2.范围for的使用条件
1. C++关键字
如图:简单认识下
2. 命名空间
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字 污染,namespace关键字的出现就是针对这种问题的。
1.命名空间定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
1.命名空间中的内容,既可以定义变量,也可以定义函数
2. 命名空间可以嵌套
3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
看以下代码理解:
#includenamespace LF { int a = 10; void test1() { printf("hello,worldn"); } namespace LL { int a = 100; int b = 90; } } void test1() { printf("hello,LFn"); } int main() { int a = 1; printf("%dn", a); test1(); return 0; } 结果: 1 hello,LF C:UsersifDesktopworldProject2DebugProject2.exe (进程 30672)已退出,代码为 0。 按任意键关闭此窗口. . .
2.命名空间使用
1.加命名空间名称及作用域限定符
printf("%dn", LF::a);
2.使用using将命名空间中成员引入
using LF::a;
3.使用using namespace 命名空间名称引入
namespace LF
{
int a = 10;
void test1()
{
printf("hello,worldn");
}
namespace LL
{
int a = 100;
int b = 90;
}
}
using namespace LF;//将命名空间引入
int main()
{
int a = 1;
printf("%dn",a);//,即使将LF展开,依然局部变量优先
printf("%dn", LF::a);
printf("%dn", LL::a);//只有展开LF,才可以使用LL;
return 0;
}
结果:
1
10
100
C:UsersifDesktopworldProject2DebugProject2.exe (进程 27872)已退出,代码为 0。
按任意键关闭此窗口. . .
3. C++输入&输出
#include
using namespace std;
int main()
{
cout<<"Hello world!!!"<
1.使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。
2. 使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c
int main()
{
int a = 0;
double p = 0;
cin >> a;
cin >> p;
cout << a <
4. 缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
全缺省:
void Test(int a = 100,int b=90)
{
cout << a << endl;
cout << b << endl;
}
int main()
{
Test(); // 没有传参时,使用参数的默认值
Test(10); // 传参时,使用指定的实参
}
结果:
100
90
10
90
半缺省:
void TestFunc(int a, int b = 10, int c = 20)
{
cout<<"a = "<
1. 因为实参是从右往左传所以半缺省参数可以省略左边,不能省略右边,不能间隔给
2. 缺省参数不能在函数声明和定义中同时出现
3. C语言不支持(编译器不支持)
5.函数重载
1.什么是函数重载
函数重载 : 是函数的一种特殊情况, C++ 允许在同一作用域中 声明几个功能类似 的同名函数 ,这些同名函数的形参列表 ( 参数个数 或 类型 或 有不同类型的参数的顺序 ) 必须不同 ,常用来处理实现功能类似数据类型不同的问题
举例:
void Func(int a, double b)
{
cout << a << b << endl;
}
void Func(double a, int b)
{
cout << a << b << endl;
}
void Pt(int a)
{
cout << a << endl;
}
void Pt(double a)
{
cout << a << endl;
}
为什么C++支持函数重载,而C
语言不支持函数重载呢?
在
C/C++
中,一个程序要运行起来,需要经历以下几个阶段:
预处理、编译、汇编、链接
当前
a.cpp
中调用了
b.cpp
中定义的
Add
函数时,编译后链接前,
a.o
的目标文件中没有
Add
的函数地址,因为
Add
是在
b.cpp中定义的。
链接器看到
a.o
调用
Add
,但是没有
Add
的地址,就会到
b.o
的符
号表中找
Add
的地址,然后链接到一起。面对
Add
函数,链接器会使用名字去找。
每个编译器都有自己的函数名修饰规
则。
如图:
c语言编译后的结果:
c++编译后的结果:
C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就可以支持重载。
2.extern “C
解释:有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器, 将该函数按照C语言规则来编译。
用法:
第一:添加在函数声明的前面
第二:extern “C”再用花括号将函数声明括起来。
经过上面的函数名修饰规则,我们知道C语言编译的库是没有改函数名的,而C++调用时会修改函数名(把函数参数与函数名结合),当用C++直接调用C库,在链接时,一个修改过的函数名,去符号表里找没被修改过的函数,显然是找不到的,这时会产生链接错误。
C如何调用C++的静态库:extern “C”将C++中的头文件中的函数声明括起来,然后生成c++的库,c语言再去调用这个生成的库,但c语言包含的c++的头文件中有extern “C”,c语言编译器识别不了,因此需要用到条件编译,将c语言包含c++头文件中的extern “C”去除。
例如:
#ifdef __cplusplus
extern "C"
{
#endif
//头文件声明
..........
..........
#ifdef __cplusplus
}
#endif
6.引用
1.概念
引用不是新定义一个变量,而是给已存在变量取了一个别名
,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
举例:
int main()
{
int a = 9;
int& p = a;
printf("%dn", p);
printf("%pn", &p);
printf("%pn", &a);
return 0;
}
结果:
9
000000A93B6FF6C4
000000A93B6FF6C4
2.引用特性
1.一个变量可以有多个引用
2.引用在定义时要初始化
3.引用一旦引用一个实体,再不能引用其他实体
3.常引用
1.引用后变量的权限只能缩小,不能够放大
只读变量 不能 引用后变为可读可写变量
2.常量也可以被引用
3.引用也可用于不同的类型数据中
此处要加上const修饰int&p,原因:在类型转换中,不是直接转换的,此处为例(double类型的数据转为int型,是把double类型数据中的整数部分存到一个临时变量中去,临时变量是具有常性的,再把临时变量中的值拷贝到p中)
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.
引用
在初始化时引用一个实体后,就
不能再引用其他实体
,而指针可以在任何时候指向任何一个同类型实体
2.
在
sizeof
中含义不同
:
引用
结果为
引用类型的大小
,但
指针
始终是
地址空间所占字节个数
(32
位平台下占4个字节
)
3.
引用自加即引用的实体增加
1
,指针自加即指针向后偏移一个类型的大小
7.内联函数
概念:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销, 内联函数提升程序运行的效率。
在release模式下,查看编译器生成的汇编代码中是否存在call Add
特性:
1. inline
是一种
以空间换时间
的做法,省去调用函数额开销。所以
代码很长
或者有
循环
/
递归
的函数不适宜
使用作为内联函数。
2.
inline
对于编译器而言只是一个建议
,编译器会自动优化,如果定义为
inline
的函数体内有循环
/
递归等
等,编译器优化时会忽略掉内联。
3. inline
不建议声明和定义分离,分离会导致链接错误。因为
inline
被展开,就没有函数地址了,链接就会找不到。
8.auto关键字(C++11)
1.概念,用法
概括:在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型 符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
注意:使用
auto
定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导
auto
的实际类
型
。因此
auto
并非是一种
“
类型
”
的声明,而是一个类型声明时的
“
占位符
”
,编译器在编译期会将
auto
替换为
变量实际的类型
。
1.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对
第一个类型进行推导,然后用推导出来的类型定义其他变量
。
2.用
auto
声明指针类型时,用
auto
和
auto*
没有任何区别,但用
auto
声明引用类型时则必须加
&
2.auto不能推导的场景
1. auto不能作为函数的参数
void Test(auto a)
{
}
//会报错
2.
auto
不能直接用来声明数组
void Test()
{
int a[] = {1,2,3,4,5,6};
auto b[] = {4,5,6,7,8};//此语言报错
}
3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
3.基于范围的for循环(C++11)
1. 范围for的语法
auto是取array中的数据,赋值给e,自动判断结束,并没有修改原数组的内容
对于一个
有范围的集合
而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11
中 引入了基于范围的for
循环。
for
循环后的括号由冒号
“
:
分为两部分:第一部分是范围内用于迭代的变量,
第二部分则表示被迭代的范围。与普通循环类似,可以用
continue
来结束本次循环,也可以用
break
来跳出整个循环
2.范围for的使用条件
1.范围for迭代的范围必须是确定的
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <
2. 迭代的对象要实现++和==的操作
printf("%dn", LF::a);
2.使用using将命名空间中成员引入
using LF::a;
3.使用using namespace 命名空间名称引入
namespace LF
{
int a = 10;
void test1()
{
printf("hello,worldn");
}
namespace LL
{
int a = 100;
int b = 90;
}
}
using namespace LF;//将命名空间引入
int main()
{
int a = 1;
printf("%dn",a);//,即使将LF展开,依然局部变量优先
printf("%dn", LF::a);
printf("%dn", LL::a);//只有展开LF,才可以使用LL;
return 0;
}
结果:
1
10
100
C:UsersifDesktopworldProject2DebugProject2.exe (进程 27872)已退出,代码为 0。
按任意键关闭此窗口. . .
3. C++输入&输出
#include
using namespace std;
int main()
{
cout<<"Hello world!!!"<
1.使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。
2. 使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c
int main()
{
int a = 0;
double p = 0;
cin >> a;
cin >> p;
cout << a <
4. 缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
全缺省:
void Test(int a = 100,int b=90)
{
cout << a << endl;
cout << b << endl;
}
int main()
{
Test(); // 没有传参时,使用参数的默认值
Test(10); // 传参时,使用指定的实参
}
结果:
100
90
10
90
半缺省:
void TestFunc(int a, int b = 10, int c = 20)
{
cout<<"a = "<
1. 因为实参是从右往左传所以半缺省参数可以省略左边,不能省略右边,不能间隔给
2. 缺省参数不能在函数声明和定义中同时出现
3. C语言不支持(编译器不支持)
5.函数重载
1.什么是函数重载
函数重载 : 是函数的一种特殊情况, C++ 允许在同一作用域中 声明几个功能类似 的同名函数 ,这些同名函数的形参列表 ( 参数个数 或 类型 或 有不同类型的参数的顺序 ) 必须不同 ,常用来处理实现功能类似数据类型不同的问题
举例:
void Func(int a, double b)
{
cout << a << b << endl;
}
void Func(double a, int b)
{
cout << a << b << endl;
}
void Pt(int a)
{
cout << a << endl;
}
void Pt(double a)
{
cout << a << endl;
}
为什么C++支持函数重载,而C
语言不支持函数重载呢?
在
C/C++
中,一个程序要运行起来,需要经历以下几个阶段:
预处理、编译、汇编、链接
当前
a.cpp
中调用了
b.cpp
中定义的
Add
函数时,编译后链接前,
a.o
的目标文件中没有
Add
的函数地址,因为
Add
是在
b.cpp中定义的。
链接器看到
a.o
调用
Add
,但是没有
Add
的地址,就会到
b.o
的符
号表中找
Add
的地址,然后链接到一起。面对
Add
函数,链接器会使用名字去找。
每个编译器都有自己的函数名修饰规
则。
如图:
c语言编译后的结果:
c++编译后的结果:
C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就可以支持重载。
2.extern “C
解释:有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器, 将该函数按照C语言规则来编译。
用法:
第一:添加在函数声明的前面
第二:extern “C”再用花括号将函数声明括起来。
经过上面的函数名修饰规则,我们知道C语言编译的库是没有改函数名的,而C++调用时会修改函数名(把函数参数与函数名结合),当用C++直接调用C库,在链接时,一个修改过的函数名,去符号表里找没被修改过的函数,显然是找不到的,这时会产生链接错误。
C如何调用C++的静态库:extern “C”将C++中的头文件中的函数声明括起来,然后生成c++的库,c语言再去调用这个生成的库,但c语言包含的c++的头文件中有extern “C”,c语言编译器识别不了,因此需要用到条件编译,将c语言包含c++头文件中的extern “C”去除。
例如:
#ifdef __cplusplus
extern "C"
{
#endif
//头文件声明
..........
..........
#ifdef __cplusplus
}
#endif
6.引用
1.概念
引用不是新定义一个变量,而是给已存在变量取了一个别名
,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
举例:
int main()
{
int a = 9;
int& p = a;
printf("%dn", p);
printf("%pn", &p);
printf("%pn", &a);
return 0;
}
结果:
9
000000A93B6FF6C4
000000A93B6FF6C4
2.引用特性
1.一个变量可以有多个引用
2.引用在定义时要初始化
3.引用一旦引用一个实体,再不能引用其他实体
3.常引用
1.引用后变量的权限只能缩小,不能够放大
只读变量 不能 引用后变为可读可写变量
2.常量也可以被引用
3.引用也可用于不同的类型数据中
此处要加上const修饰int&p,原因:在类型转换中,不是直接转换的,此处为例(double类型的数据转为int型,是把double类型数据中的整数部分存到一个临时变量中去,临时变量是具有常性的,再把临时变量中的值拷贝到p中)
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.
引用
在初始化时引用一个实体后,就
不能再引用其他实体
,而指针可以在任何时候指向任何一个同类型实体
2.
在
sizeof
中含义不同
:
引用
结果为
引用类型的大小
,但
指针
始终是
地址空间所占字节个数
(32
位平台下占4个字节
)
3.
引用自加即引用的实体增加
1
,指针自加即指针向后偏移一个类型的大小
7.内联函数
概念:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销, 内联函数提升程序运行的效率。
在release模式下,查看编译器生成的汇编代码中是否存在call Add
特性:
1. inline
是一种
以空间换时间
的做法,省去调用函数额开销。所以
代码很长
或者有
循环
/
递归
的函数不适宜
使用作为内联函数。
2.
inline
对于编译器而言只是一个建议
,编译器会自动优化,如果定义为
inline
的函数体内有循环
/
递归等
等,编译器优化时会忽略掉内联。
3. inline
不建议声明和定义分离,分离会导致链接错误。因为
inline
被展开,就没有函数地址了,链接就会找不到。
8.auto关键字(C++11)
1.概念,用法
概括:在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型 符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
注意:使用
auto
定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导
auto
的实际类
型
。因此
auto
并非是一种
“
类型
”
的声明,而是一个类型声明时的
“
占位符
”
,编译器在编译期会将
auto
替换为
变量实际的类型
。
1.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对
第一个类型进行推导,然后用推导出来的类型定义其他变量
。
2.用
auto
声明指针类型时,用
auto
和
auto*
没有任何区别,但用
auto
声明引用类型时则必须加
&
2.auto不能推导的场景
1. auto不能作为函数的参数
void Test(auto a)
{
}
//会报错
2.
auto
不能直接用来声明数组
void Test()
{
int a[] = {1,2,3,4,5,6};
auto b[] = {4,5,6,7,8};//此语言报错
}
3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
3.基于范围的for循环(C++11)
1. 范围for的语法
auto是取array中的数据,赋值给e,自动判断结束,并没有修改原数组的内容
对于一个
有范围的集合
而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11
中 引入了基于范围的for
循环。
for
循环后的括号由冒号
“
:
分为两部分:第一部分是范围内用于迭代的变量,
第二部分则表示被迭代的范围。与普通循环类似,可以用
continue
来结束本次循环,也可以用
break
来跳出整个循环
2.范围for的使用条件
1.范围for迭代的范围必须是确定的
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <
2. 迭代的对象要实现++和==的操作
namespace LF
{
int a = 10;
void test1()
{
printf("hello,worldn");
}
namespace LL
{
int a = 100;
int b = 90;
}
}
using namespace LF;//将命名空间引入
int main()
{
int a = 1;
printf("%dn",a);//,即使将LF展开,依然局部变量优先
printf("%dn", LF::a);
printf("%dn", LL::a);//只有展开LF,才可以使用LL;
return 0;
}
结果:
1
10
100
C:UsersifDesktopworldProject2DebugProject2.exe (进程 27872)已退出,代码为 0。
按任意键关闭此窗口. . .
3. C++输入&输出
#include
using namespace std;
int main()
{
cout<<"Hello world!!!"<
1.使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。
2. 使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c
int main()
{
int a = 0;
double p = 0;
cin >> a;
cin >> p;
cout << a <
4. 缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
全缺省:
void Test(int a = 100,int b=90)
{
cout << a << endl;
cout << b << endl;
}
int main()
{
Test(); // 没有传参时,使用参数的默认值
Test(10); // 传参时,使用指定的实参
}
结果:
100
90
10
90
半缺省:
void TestFunc(int a, int b = 10, int c = 20)
{
cout<<"a = "<
1. 因为实参是从右往左传所以半缺省参数可以省略左边,不能省略右边,不能间隔给
2. 缺省参数不能在函数声明和定义中同时出现
3. C语言不支持(编译器不支持)
5.函数重载
1.什么是函数重载
函数重载 : 是函数的一种特殊情况, C++ 允许在同一作用域中 声明几个功能类似 的同名函数 ,这些同名函数的形参列表 ( 参数个数 或 类型 或 有不同类型的参数的顺序 ) 必须不同 ,常用来处理实现功能类似数据类型不同的问题
举例:
void Func(int a, double b)
{
cout << a << b << endl;
}
void Func(double a, int b)
{
cout << a << b << endl;
}
void Pt(int a)
{
cout << a << endl;
}
void Pt(double a)
{
cout << a << endl;
}
为什么C++支持函数重载,而C
语言不支持函数重载呢?
在
C/C++
中,一个程序要运行起来,需要经历以下几个阶段:
预处理、编译、汇编、链接
当前
a.cpp
中调用了
b.cpp
中定义的
Add
函数时,编译后链接前,
a.o
的目标文件中没有
Add
的函数地址,因为
Add
是在
b.cpp中定义的。
链接器看到
a.o
调用
Add
,但是没有
Add
的地址,就会到
b.o
的符
号表中找
Add
的地址,然后链接到一起。面对
Add
函数,链接器会使用名字去找。
每个编译器都有自己的函数名修饰规
则。
如图:
c语言编译后的结果:
c++编译后的结果:
C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就可以支持重载。
2.extern “C
解释:有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器, 将该函数按照C语言规则来编译。
用法:
第一:添加在函数声明的前面
第二:extern “C”再用花括号将函数声明括起来。
经过上面的函数名修饰规则,我们知道C语言编译的库是没有改函数名的,而C++调用时会修改函数名(把函数参数与函数名结合),当用C++直接调用C库,在链接时,一个修改过的函数名,去符号表里找没被修改过的函数,显然是找不到的,这时会产生链接错误。
C如何调用C++的静态库:extern “C”将C++中的头文件中的函数声明括起来,然后生成c++的库,c语言再去调用这个生成的库,但c语言包含的c++的头文件中有extern “C”,c语言编译器识别不了,因此需要用到条件编译,将c语言包含c++头文件中的extern “C”去除。
例如:
#ifdef __cplusplus
extern "C"
{
#endif
//头文件声明
..........
..........
#ifdef __cplusplus
}
#endif
6.引用
1.概念
引用不是新定义一个变量,而是给已存在变量取了一个别名
,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
举例:
int main()
{
int a = 9;
int& p = a;
printf("%dn", p);
printf("%pn", &p);
printf("%pn", &a);
return 0;
}
结果:
9
000000A93B6FF6C4
000000A93B6FF6C4
2.引用特性
1.一个变量可以有多个引用
2.引用在定义时要初始化
3.引用一旦引用一个实体,再不能引用其他实体
3.常引用
1.引用后变量的权限只能缩小,不能够放大
只读变量 不能 引用后变为可读可写变量
2.常量也可以被引用
3.引用也可用于不同的类型数据中
此处要加上const修饰int&p,原因:在类型转换中,不是直接转换的,此处为例(double类型的数据转为int型,是把double类型数据中的整数部分存到一个临时变量中去,临时变量是具有常性的,再把临时变量中的值拷贝到p中)
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.
引用
在初始化时引用一个实体后,就
不能再引用其他实体
,而指针可以在任何时候指向任何一个同类型实体
2.
在
sizeof
中含义不同
:
引用
结果为
引用类型的大小
,但
指针
始终是
地址空间所占字节个数
(32
位平台下占4个字节
)
3.
引用自加即引用的实体增加
1
,指针自加即指针向后偏移一个类型的大小
7.内联函数
概念:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销, 内联函数提升程序运行的效率。
在release模式下,查看编译器生成的汇编代码中是否存在call Add
特性:
1. inline
是一种
以空间换时间
的做法,省去调用函数额开销。所以
代码很长
或者有
循环
/
递归
的函数不适宜
使用作为内联函数。
2.
inline
对于编译器而言只是一个建议
,编译器会自动优化,如果定义为
inline
的函数体内有循环
/
递归等
等,编译器优化时会忽略掉内联。
3. inline
不建议声明和定义分离,分离会导致链接错误。因为
inline
被展开,就没有函数地址了,链接就会找不到。
8.auto关键字(C++11)
1.概念,用法
概括:在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型 符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
注意:使用
auto
定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导
auto
的实际类
型
。因此
auto
并非是一种
“
类型
”
的声明,而是一个类型声明时的
“
占位符
”
,编译器在编译期会将
auto
替换为
变量实际的类型
。
1.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对
第一个类型进行推导,然后用推导出来的类型定义其他变量
。
2.用
auto
声明指针类型时,用
auto
和
auto*
没有任何区别,但用
auto
声明引用类型时则必须加
&
2.auto不能推导的场景
1. auto不能作为函数的参数
void Test(auto a)
{
}
//会报错
2.
auto
不能直接用来声明数组
void Test()
{
int a[] = {1,2,3,4,5,6};
auto b[] = {4,5,6,7,8};//此语言报错
}
3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
3.基于范围的for循环(C++11)
1. 范围for的语法
auto是取array中的数据,赋值给e,自动判断结束,并没有修改原数组的内容
对于一个
有范围的集合
而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11
中 引入了基于范围的for
循环。
for
循环后的括号由冒号
“
:
分为两部分:第一部分是范围内用于迭代的变量,
第二部分则表示被迭代的范围。与普通循环类似,可以用
continue
来结束本次循环,也可以用
break
来跳出整个循环
2.范围for的使用条件
1.范围for迭代的范围必须是确定的
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <
2. 迭代的对象要实现++和==的操作
1.使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。
2. 使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c
int main()
{
int a = 0;
double p = 0;
cin >> a;
cin >> p;
cout << a <
4. 缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
全缺省:
void Test(int a = 100,int b=90)
{
cout << a << endl;
cout << b << endl;
}
int main()
{
Test(); // 没有传参时,使用参数的默认值
Test(10); // 传参时,使用指定的实参
}
结果:
100
90
10
90
半缺省:
void TestFunc(int a, int b = 10, int c = 20)
{
cout<<"a = "<
1. 因为实参是从右往左传所以半缺省参数可以省略左边,不能省略右边,不能间隔给
2. 缺省参数不能在函数声明和定义中同时出现
3. C语言不支持(编译器不支持)
5.函数重载
1.什么是函数重载
函数重载 : 是函数的一种特殊情况, C++ 允许在同一作用域中 声明几个功能类似 的同名函数 ,这些同名函数的形参列表 ( 参数个数 或 类型 或 有不同类型的参数的顺序 ) 必须不同 ,常用来处理实现功能类似数据类型不同的问题
举例:
void Func(int a, double b)
{
cout << a << b << endl;
}
void Func(double a, int b)
{
cout << a << b << endl;
}
void Pt(int a)
{
cout << a << endl;
}
void Pt(double a)
{
cout << a << endl;
}
为什么C++支持函数重载,而C
语言不支持函数重载呢?
在
C/C++
中,一个程序要运行起来,需要经历以下几个阶段:
预处理、编译、汇编、链接
当前
a.cpp
中调用了
b.cpp
中定义的
Add
函数时,编译后链接前,
a.o
的目标文件中没有
Add
的函数地址,因为
Add
是在
b.cpp中定义的。
链接器看到
a.o
调用
Add
,但是没有
Add
的地址,就会到
b.o
的符
号表中找
Add
的地址,然后链接到一起。面对
Add
函数,链接器会使用名字去找。
每个编译器都有自己的函数名修饰规
则。
如图:
c语言编译后的结果:
c++编译后的结果:
C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就可以支持重载。
2.extern “C
解释:有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器, 将该函数按照C语言规则来编译。
用法:
第一:添加在函数声明的前面
第二:extern “C”再用花括号将函数声明括起来。
经过上面的函数名修饰规则,我们知道C语言编译的库是没有改函数名的,而C++调用时会修改函数名(把函数参数与函数名结合),当用C++直接调用C库,在链接时,一个修改过的函数名,去符号表里找没被修改过的函数,显然是找不到的,这时会产生链接错误。
C如何调用C++的静态库:extern “C”将C++中的头文件中的函数声明括起来,然后生成c++的库,c语言再去调用这个生成的库,但c语言包含的c++的头文件中有extern “C”,c语言编译器识别不了,因此需要用到条件编译,将c语言包含c++头文件中的extern “C”去除。
例如:
#ifdef __cplusplus
extern "C"
{
#endif
//头文件声明
..........
..........
#ifdef __cplusplus
}
#endif
6.引用
1.概念
引用不是新定义一个变量,而是给已存在变量取了一个别名
,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
举例:
int main()
{
int a = 9;
int& p = a;
printf("%dn", p);
printf("%pn", &p);
printf("%pn", &a);
return 0;
}
结果:
9
000000A93B6FF6C4
000000A93B6FF6C4
2.引用特性
1.一个变量可以有多个引用
2.引用在定义时要初始化
3.引用一旦引用一个实体,再不能引用其他实体
3.常引用
1.引用后变量的权限只能缩小,不能够放大
只读变量 不能 引用后变为可读可写变量
2.常量也可以被引用
3.引用也可用于不同的类型数据中
此处要加上const修饰int&p,原因:在类型转换中,不是直接转换的,此处为例(double类型的数据转为int型,是把double类型数据中的整数部分存到一个临时变量中去,临时变量是具有常性的,再把临时变量中的值拷贝到p中)
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.
引用
在初始化时引用一个实体后,就
不能再引用其他实体
,而指针可以在任何时候指向任何一个同类型实体
2.
在
sizeof
中含义不同
:
引用
结果为
引用类型的大小
,但
指针
始终是
地址空间所占字节个数
(32
位平台下占4个字节
)
3.
引用自加即引用的实体增加
1
,指针自加即指针向后偏移一个类型的大小
7.内联函数
概念:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销, 内联函数提升程序运行的效率。
在release模式下,查看编译器生成的汇编代码中是否存在call Add
特性:
1. inline
是一种
以空间换时间
的做法,省去调用函数额开销。所以
代码很长
或者有
循环
/
递归
的函数不适宜
使用作为内联函数。
2.
inline
对于编译器而言只是一个建议
,编译器会自动优化,如果定义为
inline
的函数体内有循环
/
递归等
等,编译器优化时会忽略掉内联。
3. inline
不建议声明和定义分离,分离会导致链接错误。因为
inline
被展开,就没有函数地址了,链接就会找不到。
8.auto关键字(C++11)
1.概念,用法
概括:在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型 符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
注意:使用
auto
定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导
auto
的实际类
型
。因此
auto
并非是一种
“
类型
”
的声明,而是一个类型声明时的
“
占位符
”
,编译器在编译期会将
auto
替换为
变量实际的类型
。
1.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对
第一个类型进行推导,然后用推导出来的类型定义其他变量
。
2.用
auto
声明指针类型时,用
auto
和
auto*
没有任何区别,但用
auto
声明引用类型时则必须加
&
2.auto不能推导的场景
1. auto不能作为函数的参数
void Test(auto a)
{
}
//会报错
2.
auto
不能直接用来声明数组
void Test()
{
int a[] = {1,2,3,4,5,6};
auto b[] = {4,5,6,7,8};//此语言报错
}
3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
3.基于范围的for循环(C++11)
1. 范围for的语法
auto是取array中的数据,赋值给e,自动判断结束,并没有修改原数组的内容
对于一个
有范围的集合
而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11
中 引入了基于范围的for
循环。
for
循环后的括号由冒号
“
:
分为两部分:第一部分是范围内用于迭代的变量,
第二部分则表示被迭代的范围。与普通循环类似,可以用
continue
来结束本次循环,也可以用
break
来跳出整个循环
2.范围for的使用条件
1.范围for迭代的范围必须是确定的
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <
2. 迭代的对象要实现++和==的操作



