目录
C++关键字:
C语言有32个关键字(c90),C++有63个关键字(c++98)。
命名空间:
定义:
表示一个标识符的可见范围,使用namespace{ }的形式定义。
注意:
namespace N1{
int a = 1;
int add(int left, int right) {
return left + right;
}
namespace N2 {
int b = 0;
}
}
命名空间中成员的使用:
1、加命名空间名称及作用域限定符(空间名称:: 变量名)
namespace N1{
int a = 1;
int add(int left, int right) {
return left + right;
}
namespace N2 {
int b = 0;
}
}
int main() {
printf("%d\n", N1::add(1, 3));
system("pause");
return 0;
}
2、使用using将命名空间中的成员引入
namespace N1{
int a = 1;
int add(int left, int right) {
return left + right;
}
namespace N2 {
int b = 0;
}
}
using N1::add;
int main() {
printf("%d\n", add(1, 3));
system("pause");
return 0;
}
3、using namespace 空间名称
namespace N1{
int a = 1;
int add(int left, int right) {
return left + right;
}
namespace N2 {
int b = 0;
}
}
//using N1::add;
using namespace N1;
int main() {
printf("%d\n", add(a, 3));
system("pause");
return 0;
}
在日常练习中使用3,在项目中使用1或者2,其目的是为了避免发生冲突。
输入输出
using namespace std;
int main() {
//printf("%d\n", add(a, 3));
cout << "hello world"<<endl;
system("pause");
return 0;
}
缺省参数
概念:
声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
using namespace std;
void func(int a = 10) {
cout << a << endl;
}
int main() {
//printf("%d\n", add(a, 3));
func(); // 10
func(1); // 1
system("pause");
return 0;
}
函数重载
概念:
作用:
处理实现功能类似数据类型不同的问题。
为什么c++支持函数重载,而c语言不支持函数重载?
在C/C++中,一个程序要运行起来,需要经历以下四个阶段:
在链接过程中,遇到函数调用时会通过查看符号表到对应的库或者时其他声明该函数的地方去找。 此时,连接器会使用哪个名字去找?每个编译器都有自己的函数名称修饰规则。
linux下的gcc和g++:
gcc函数修饰后名字不变;而g++的函数修饰后函数名字发生改变,变成【_Z + 函数长度 + 类型首字母】。
Windows下:
c程序编译后函数修饰名字不变。c++程序对函数名字的修饰则非常复杂,但是其目的是一样的。
重载过程:
①编译器拿用户传入的参数与已经定义的函数参数对比
②如果参数对应完全一致,直接调用该函数
③若没有参数完全一致的重载函数,则默认的对用户的参数进行隐式类型转化
④转化之后若有适合的重载函数,编译通过。否则直接报错!
extern “C”:
有时候c++工程中可能需要将某些函数按照c的风格来编译。在函数前加extern “C”是告诉编译器,将该函数按照C语言的风格来编译。
注意:
引用
概念:
引用不是定义一个新的变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
int main() {
int a = 1;
int& ra = a;
cout << a << endl;
cout << ra << endl;
cout << &a << endl;
cout << &a << endl;
system("pause");
}
特性:
常引用:
int main() {
const int a = 10;
//int& ra = a; 编译时会出错,因为此时a为一个常量
const int& ra = a;
//int& b = 2; 编译时会出错,b为常量
const int& b = 2;
double c = 3.14;
//int& rc = c; 编译出错
const int& rc = c; //rc并不是c的别名,而是而是该过程产生的临时变量的别名
//在此过程中会创建一个int类型的临时变量,临时变量具有常性,因此加上const后就不会报错
}
引用的使用场景
1、做参数
void swap(int& left, int& right) {
int temp;
temp = left;
left = right;
right = temp;
}
int main() {
int a = 10;
int b = 20;
swap(a, b);
cout << a << endl;
cout << b << endl;
system("pause");
}
2、做返回值
int& Count()
{
static int n = 0;
n++;
return n;
}
int main() {
cout << Count() << endl;
system("pause");
}
传值和传引用的效率:
以值作为参数或者返回值类型,在传参和返回值期间,函数不会直接传递实参或者将变量直接返回,而是传递实参或者返回变量的一份临时拷贝,因此用值作为参数或者返回值类型 效率十分低下的,尤其是当参数或者返回值类型非常大的时候,效率就更低了。
引用和指针的区别:
在语法概念上,引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
下面的代码可以验证:
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
可以看出引用和指针的汇编代码时一摸一样的。
引用和指针的不同点:
内联函数
1、概念:
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序的运行效率。
如果在上述函数前加上inline关键字将其改为内联函数,在编译期间编译器会用函数体替换函数的调用。
查看方式:
1、在release模式下,查看编译器生成的汇编代码中是否存在call Add
2、在debug模式下,需要对编译i进行设置,否则不会展开。因为debug模式下,编译器默认不会对代码进行优化,下面是结局方案。
2、特性
宏的优缺点
1、宏常量
优点:一改全改;降低出错率;可读性高
缺点:不方便调试宏,因为预处理阶段进行了宏替换;如果没有类型安全的检查,安全性低,如果出错,在预处理阶段不会在宏定义处报错,而是会在使用处报错。这样会给查找错误来源造成不便。
综上所述,建议使用C++中的const常量代替宏常量。
2、宏函数
优点:并不是真正意义上的函数,不会有函数调用,提高程序的运行效率;少些代码,因为宏函数是多条语句的封装(不能提高代码的复用率,因为宏函数在预处理阶段就展开了);提高代码的可读性。
缺点:在预处理阶段被替换,不会进行类型检测,代码安全性低;不能调试;每个部分都会展开,造成代码膨胀;容易出错,每个部分都要加括号(即使加了括号,在有些特殊场景下也会出错);宏函数可能会有副作用。
建议:使用内敛函数代替宏函数(函数的写法,宏的作用)
C++有哪些技术可以代替宏?
1、常量定义换用const
2、函数定义换用内联函数
auto关键字 (C++11)
简介:
在早期C/C++中auto的含义是:使用auto修饰的变量是具有自动存储的局部变量
C++11中,标准委员会赋予了auto全新的含义:auto不再是一个存储类型指示符,而是作为一个全新的类型指示符来指示编辑器,auto声明的变量必须由编译器在编译时期推导而得。
如下:
注意:使用auto定义变量的时候必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种类型的说明,而是一个类型额声明时的“占位符”,编译器在编译阶段会将auto替换为变量实际的类型。
使用规则:
基于范围的for循环(C++)
对于一个有范围的集合而言,由程序员说明循环的范围是多余的,有时候还容易犯错误。因此C++11中引入了基于范围的for循环的括号由‘:’分为两部分,第一部分时范围内用于迭代的变量,第二部分则表示被迭代的范围:
注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。
for循环迭代的范围必须时确定的:对于数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。
空指针nullptr(C++11)
NULL实际是一个宏,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值指针时,都不可避免会遇到一些麻烦。
在C++98中,字面常量0既可以是一个整形数字,也可以时无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整型常量,如果将其按照指针方式来使用,必须对其进行强转(void*)0。
注意: