C++入门
1.命名空间
(1)命名空间定义
使用namespace关键字,后面跟命名空间的名字,然后接一对{}
//普通命名空间
namespace N1
{
int a;
int Add(int left,int right)
{
return left+right;
}
}
//命名空间可以嵌套
namespace N2
{
int a;
int b;
int Add(int left,int right)
{
return left+right;
}
namespace N3
{
int c;
int d;
int Add(int left,int right)
{
return left+right;
}
}
}
//同一个项目中可以有多个相同名称的命名空间,编译器最后会合成到一个命名空间中
namespace N1
{
int Mul(int left,int right)
{
return left+right;
}
}
- 一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
(2)命名空间使用
namespace N
{
int a = 10;
int b = 20;
int Add(int left, int right)
{
return left + right;
}
}
int main()
{
printf("%d\n",a);//编译出错,无法识别a
return 0;
}
//1.加命名空间名称及作用域限定符
int main()
{
printf("%d\n",N::a);
}
//2.使用using将命名空间中成员引入
using N::b;
int mian()
{
printf("%d\n",N::a);
printf("%d\n",b);
}
//3.使用using namespace 命名空间名称引入
using namespace N;
int main()
{
printf("%d\n",N::a);
printf("%d\n",b);
Add(10,20);
return 0;
}
2.输入输出
使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空 间。
#include<iostream>
using namespace std;
int main()
{
int a,b;
cin>>a;//输入给a
cout<<b;//将b输出
cout<<b<<endl;//先输出b再换行
return 0;
}
- c++中输入输出不需要关心数据的格式
3.缺省参数
void TestFunc(int a = 0)
{
cout<<a<<endl;
}
int main()
{
TestFunc(); // 没有传参时,使用参数的默认值
TestFunc(10); // 传参时,使用指定的实参
}
- 半缺省参数必须从右往左依次来给出,不能间隔着给
void TestFunc(int a, int b = 10, int c = 20)
- 缺省参数不能在函数声明和定义中同时出现
4.函数重载
在同一个作用域中,函数名必须相同,参数必须不同
参数列表不同:
1.参数个数
2.参数类型
3.类型的次序
与返回值类型无关
- extren"C": 意思是告诉编译器, 将该函数按照C语言规则来编译
5.引用
(1).概念:
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它 引用的变量共用同一块内存空间。
void TestRef()
{
int a=10;
int& ra= a;
printf("%p",&a);
printf("%p",&ra);
}
- 引用类型必须和引用实体是同种类型的
(2).特性
a.引用在定义时必须初始化
b.一个变量可以有多个引用
c.引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{
int a=10;
//int& ra;错误,没有初始化
int& ra=a;
int& rra=a;
printf("%p %p %p",&a,&ra,&rra);
}
(3).常引用
int main()
{
int a=10;
const int& ra=a;//不能通过ra来修改a
// int& rb=100;//100是字面常量,不能被修改
const int& rb=100;
const int c=10;
// int& rc=c;//编译失败----c是常量,给成普通类型的引用不行
const int& rc=c;
double d=12.34;
// int& rd=d;//编译错误
const int& rd=d;//rd不是d的引用,而是double到int发生了隐式类型转换,同时创建了一个临 时变量存储转化的结果(12),rd引用的是这个临时变量
}
(4)使用场景
a.作参数
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
- 如果引用传参,函数不想通过形参改变实参,最好将形参设置为const类型的引用
b.作返回值
int& Count()
{
static int n = 0;
n++;
// ...
return n;
}
- 如果函数返回时,出了函数作用域,如果返回对象还未还给系统(全局变量或static修饰),则可以使用引用返回,如果已经还给系统了(临时变量 ),则必须使用传值返回。
(5)传值、传地址、传引用效率区别
结论:转值效率低,传地址和传引用差不多
(6)指针和引用的区别:
相同点:
a.效率差不多
b.传参可以达到相同的效果-->修改形参可以改变实参
c.底层实现方式一样
不同点:
a.引用在定义时必须初始化,指针无要求
b.引用在初始化一个实体后,就不能在引用别的实体了,指针无要求
c.没有NULL引用,但有NULL指针
d.sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间的大小
e.引用自加即引用的实体加1,而指针自加是指针向后偏移一个类型的大小
f.没有多级引用,有多级指针
g.访问实体方式不同,指针需要解引用,引用是编译器自己处理
h.引用比指针更加安全
6.内联函数&宏
(1)宏
宏: #define出来的东西
宏常量:#define MAX_SIZE 100
宏函数:#define MAX(a,b) a>b?a:b
(2)const
a.C++中被const修饰的变量,已经不是变量了,而是一个常量,允许用来定义数组
const int a=10;
//int array[a] 可证明a为常量
//a=100; 报错
int* pa=(int*)&a;
*pa=100 //可通过指针修改a中的值
b.const具有宏替换的属性
(3)内联函数
以inline修饰的函数叫内联函数,编译时c++编译器会在调用内联函数的地方展开内联函数提升程序运行的效率
(4)特性
a.在编译时:会展开该函数
b.函数如果是递归、循环等比较复杂,就会忽略inline
c.inline不建议声明和定义分离,分离会导致链接错误
总结
宏的优点:
1.提高了程序的可读性,同时也方便进行修改
2.提高程序的运行效率:使用带参的宏定义既可完成函数调用的功能,又能避免函数的出栈与入栈操作,减少系统开销,提高运行效率
3. 宏是由预处理器处理的,通过字符串操作可以完成很多编译器无法实现的功能。比如##连接符
宏的缺点:
1.由于是直接嵌入的,所以 代码可能相对多一点
2.嵌套定义过多可能会影响程序的可读性,而且很容易出错
3.对带参的宏而言,由于是直接替换,并不会检查参数是否合法,存在安全隐患
- 预编译语句仅仅是简单的值代替,缺乏类型的检测机制。这样预处理语句就不能享受C++严格的类型检查的好处,从而可能成为引发一系列错误的隐患。的确,宏定义给我们带来很多方便之处,但是必须正确使用,否则,可能会出现一些意想不到的问题。
宏和内联函数的区别
1.内联函数相比较于宏而言,内联函数要做参数类型检查,从而内联函数相比宏而言更加安全
2.内联函数在运行时可调试,而宏定义不可以。
7.auto关键字
(1)概念:
auto声明的变量可以由编译器在编译阶段推导而得(根据初始化表达式来推导)
(2)特性:
a.用auto声明指针类型时,auto和auto*无区别;auto修饰引用时,auto是拷贝,auto&是实体
b.auto修饰的变量不能用作函数参数
c.auto不能声明数组
d. 当在同一行声明多个变量时,这些变量必须是相同的类型,
范围for
1.语法
int mian()
{
int array[]={1,2,3,4,5};
for(auto&e:array)
e*=2;
for(auto e:array)
cout<<e<<" "<<endl;
}
2.使用条件
for循环迭代范围必须是确定的
nullptr关键字
int* p=nullptr;//创建一个空指针