1.关键字(C++98)
2.命名空间
在
C/C++
中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是
对标识符的名称进行本地化
,
以
避免命名冲突或名字污染
,
namespace
关键字的出现就是针对这种问题的
他这样会正常显示!!!
但是如果加上#include<stdlib.h>就会报错
2.1命名空间的定义
定义命名空间,需要使用到
namespace
关键字
,后面跟
命名空间的名字
,然
后接一对
{}
即可,
{}
中即为命名空间的成员。
1. 正常的命名空间定义
namespace bit
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
int main()
{
printf("%d", bit::rand);
return 0;
}
2.命名空间的嵌套
3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
1. 正常的命名空间定义
//namespace bit
//{
// // 命名空间中可以定义变量/函数/类型
// int rand = 10;
// int Add(int left, int right)
// {
// return left + right;
// }
// struct Node
// {
// struct Node* next;
// int val;
// };
//}
//int main()
//{
// printf("%d", bit::rand);
// return 0;
//}
//2. 命名空间可以嵌套
// test.cpp
namespace N1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
//int main()
//{
// printf("%d",N1::N2::Sub(2, 3));
// return 0;
//}
//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
// ps:一个工程中的test.h和上面test.cpp中两个N1会被合并成一个
// test.h
namespace N1
{
int Mul(int left, int right)
{
return left * right;
}
}
int main()
{
return 0;
}
2.2命名空间的使用
namespace bit
{
// 命名空间中可以定义变量/函数/类型
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
int main()
{
// 编译报错:error C2065: “a”: 未声明的标识符
printf("%d\n", a);
return 0;
}
int main()
{
printf("%d\n", N::a);
return 0;
}
using N::b;
printf("%d\n", N::a);
printf("%d\n", b);
return 0;
}
using namespce N;
int main()
{
printf("%d\n", N::a);
printf("%d\n", b);
Add(10, 20);
return 0;
}
3. C++输入&输出
说明:
1.
使用
cout
标准输出对象
(
控制台
)
和
cin
标准输入对象
(
键盘
)
时,必须
包含
< iostream >
头文件
以及按命名空间使用方法使用
std
。
2. cout
和
cin
是全局的流对象,
endl
是特殊的
C++
符号,表示换行输出,他们都包含在包含
<
iostream >
头文件中。
3.
<<
是流插入运算符,
>>
是流提取运算符
。
4.
使用
C++
输入输出更方便,不需要像
printf/scanf
输入输出时那样,需要手动控制格式。
C++
的输入输出可以自动识别变量类型。
5.
实际上
cout
和
cin
分别是
ostream
和
istream
类型的对象,
>>
和
<<
也涉及运算符重载等知识,
这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有有
一个章节更深入的学习
IO
流用法及原理。
注意:早期标准库将所有功能在全局域中实现,声明在
.h
后缀的头文件中,使用时只需包含对应
头文件即可,后来将其实现在
std
命名空间下,为了和
C
头文件区分,也为了正确使用命名空间,
规定
C++
头文件不带
.h
;旧编译器
(vc 6.0)
中还支持
<iostream.h>
格式,后续编译器已不支持,因
此
推荐
使用
<iostream>+std
的方式
std
命名空间的使用惯例:
std
是
C++
标准库的命名空间,如何展开
std
使用更合理呢?
1.
在日常练习中,建议直接
using namespace std
即可,这样就很方便。
2. using namespace std
展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型
/
对
象
/
函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模
大,就很容易出现。所以建议在项目开发中使用,像
std::cout
这样使用时指定命名空间
+
using std::cout
展开常用的库对象
/
类型等方式。
4. 缺省参数
4.1 缺省参数概念
缺省参数是
声明或定义函数时
为函数的
参数指定一个缺省值
。在调用该函数时,如果没有指定实
参则采用该形参的缺省值,否则使用指定的实参。
4.2 缺省参数分类
1. 半缺省参数必须 从右往左依次 来给出,不能间隔着给2. 缺省参数不能在函数声明和定义中同时出现3. 缺省值必须是常量或者全局变量4. C 语言不支持(编译器不支持)
5. 函数重载
自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是 “ 谁也赢不了! ” ,后者是 “ 谁也赢不了
5.1 函数重载概念
// 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该
//用那个缺省值。
#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}
6. 引用
6.1应用的概念
引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空间,它和它引用的变量 共用同一块内存空间。比如: 李逵 ,在家称为 " 铁牛 " ,江湖上人称 " 黑旋风 " 。
类型& 引用变量名(对象名) = 引用实体;
注意:引用类型必须和引用实体是同种类型的
6.2 引用特性
1. 引用在 定义时必须初始化2. 一个变量可以有多个引用3. 引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{
int a = 10;
// int& ra; // 该条语句编译时会出错
int& ra = a;
int& rra = a;
printf("%p %p %p\n", &a, &ra, &rra);
}
6.3 常引用
6.4 使用场景
1. 做参数
2. 做返回值
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
return 0;
}
注意: 如果函数返回时,出了函数作用域,如果返回对象还在 ( 还没还给系统 ) ,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
6.5 传值、传引用效率比较
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直 接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{
A a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
return 0;
}
6.6 引用和指针的区别
引用和指针的不同点
:
1.
引用概念上定义一个变量的别名,指针存储一个变量地址。
2.
引用
在定义时
必须初始化
,指针没有要求
3.
引用
在初始化时引用一个实体后,就
不能再引用其他实体
,而指针可以在任何时候指向任何
一个同类型实体
4.
没有
NULL
引用
,但有
NULL
指针
5.
在
sizeof
中含义不同
:
引用
结果为
引用类型的大小
,但
指针
始终是
地址空间所占字节个数
(32
位平台下占
4
个字节
)
6.
引用自加即引用的实体增加
1
,指针自加即指针向后偏移一个类型的大小
int main()
{
int a = 10;
int& ra = a;
cout<<"&a = "<<&a<<endl;
cout<<"&ra = "<<&ra<<endl;
return 0;
}
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
7.
有多级指针,但是没有多级引用
8.
访问实体方式不同,
指针需要显式解引用,引用编译器自己处理
9.
引用比指针使用起来相对更安全