目录
C++关键字
我们知道在C语言中只有32个关键字,而C++中有63个关键字
asm | do | if | return | try | continue |
auto | double | inline | short | typedef | for |
bool | dynamic_cast | int | signed | typeid | public |
break | else | long | sizeof | typename | throw |
case | enum | mutable | static | union | wchar_t |
catch | explicit | namespace | static_cast | unsigned | default |
char | export | new | struct | using | friend |
class | extern | operator | switch | virtual | register |
const | false | private | template | void | true |
const_cast | float | protected | this | volatile | while |
delete | goto | reinterpret_cast |
C++命名空间
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。 使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的.
因为在C语言中,存在一个名为rand()的函数,此时若将变量名定义为rand会与标准库中rand()函数名产生冲突,而C语言能解决这个问题方法只有更改变量名,否则没有其他办法.
但是在C++中,可以使用命名空间解决这个问题.
所谓命名空间指当前命名的变量所处的空间,在命名空间中,可以声明变量/类型/函数,例如:
//命名空间1
namespace ns1
{
//变量
int rand = 1;
//函数
int add(int x, int y)
{
return x + y;
}
//类型
struct Node
{
struct Node* next;
int val;
};
//命名空间2
namespace ns2
{
int a = 2;//命名函数的嵌套
}
}
运行结果如下:
域作用限定符
在C++中,::表示域作用限定符,使用方法如下:
空间::变量/类型/对象名
在::左边什么也没有时,是默认在全局中寻找::右侧的内容的。
如下:
当然如果没有全局变量他也是不会去局部变量找的
如下:
由此可以得知 在::左边什么也没有时它会在全局变量中进行查找;
命名空间除了上述方法还有两种使用方法:
使用using将命名空间中某个成员引入,也称部分展开,例如using ns1::a
使用using将命名空间整体引入,也称全局展开,例如using namespace ns1
代码如下:
//命名空间1
namespace ns1
{
//变量
int i = 1;
//函数
int add(int x, int y)
{
return x + y;
}
//类型
struct Node
{
struct Node* next;
int val;
};
//命名空间2
namespace ns2
{
int a = 2;//命名函数的嵌套
}
}
using namespace ns1;//全局展开
int main()
{
printf("%d %d \n", i, ns2::a);
return 0;
}
运行结果如图:
部分展开如下:
//命名空间1
namespace ns1
{
//变量
int i = 1;
//函数
int add(int x, int y)
{
return x + y;
}
//类型
struct Node
{
struct Node* next;
int val;
};
//命名空间2
namespace ns2
{
int a = 2;//命名函数的嵌套
}
}
using ns1::ns2::a;
可看出 没有展开 i 是不能直接输出的 :
当存在两个相同的命名空间时,会被合并成一个命名空间,而不是直接覆盖,例如:
C++的输入输出
C++中 可以使用cout和cin配合流插入运算符‘<<’和流提取运算符‘>>’使用,不过必须包含
< iostream >头文件
以及按命名空间使用方法使用std 。
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
//也可以使用 using namespace std;
int main()
{
int a = 0;
cout << a << endl;//endl 是C++中的换行
cout << "请输入a的值:" << "\n";//也可以使用\n进行换行
cin >> a;
cout << a << endl;
return 0;
}
在C++中,输入和输出可以自动识别变量类型,所以输出和输入不需要占位符。
运行结果如下:
C++中的缺省参数
在C++中,缺省参数有两种,第一种是全缺省参数,第二种是半缺省参数。
在使用缺省参数时,必须遵循从右往左连续使用,不可以跳跃式使用,
全缺省参数使用如下:
void f1(int i = 1, int a = 2, int b = 3)
{
cout << i << " " << a << " " << b << '\n';
}
int main()
{
f1(10, 20, 30);//不使用缺省值
f1(10, 20);//使用第三个缺省值
f1(10);//使用第二个和第三个缺省值
f1();//使用全部缺省值
return 0;
}
运行结果如下:
“从右往左使用”意思是,当调用函数给函数传递实际参数时,第一个实参对应着第一个第一个形参,第二个实参对应着第二个形参,第三个实参对应着第三个形参,使用缺省参数时,当只传递一个实际参数时,该实际参数对应着第一个形参,此时使用第二个和第三个缺省参数,同理,当传递两个实际参数时,两个实际参数对应的前两个形参,使用第三个缺省参数,即总是满足最右边的缺省参数是第一个使用的 。
半缺省参数指的是在函数的定义中有部分变量是缺省参数。
下面这两种写法是错误的,给缺省参数需要满足从右往左依次给,不能跳跃着给。
void f1(int i = 10, int a , int b = 30 )
{
cout << i << " " << a << " " << b << '\n';
}
void f1(int i = 10, int a , int b )
{
cout << i << " " << a << " " << b << '\n';
}
正确写法如下:
void f1(int i, int a , int b = 30 )
{
cout << i << " " << a << " " << b << '\n';
}
void f1(int i, int a = 20 , int b = 30 )
{
cout << i << " " << a << " " << b << '\n';
}
半缺省参数使用如下:
void f1(int i, int a = 2, int b = 3)
{
cout << i << " " << a << " " << b << '\n';
}
int main()
{
f1(10, 20, 30);//不使用任何缺省参数
f1(10, 20);//使用最后一个缺省参数
f1(10);//使用最后两个缺省参数 10 是给形参传的值
return 0;
}
在使用半缺省参数时,必须满足从右往左依次使用缺省参数,不能跳跃式使用。
这种写法就是错误的。
还有一种就是声名与定义分离时该如何使用缺省参数:
//stack.cpp
#include"stack.h"
void stack::Init(int n)// 这里需要指定Init是属于stack这个类域
{
arr = (int*)malloc(sizeof(int) * n);
if (arr == nullptr)
{
perror("malloc fail");
return;
}
capacity = n;
top = 0;
}
//stack.cpp
#include<stdlib.h>
#include<iostream>
using namespace std;
class stack
{
public:
//成员函数
void Init(int n = 4);
void push(int x);
private:
//成员变量
int* arr;
size_t capacity;
size_t top;
};
//***.cpp
#include"stack.h"
int main()
{
stack st1;
st1.Init();
return 0;
}
1. 函数声明和函数定义分离时不能同时设置缺省参数:
2. 缺省参数以函数声明为准,函数定义中的缺省参数无效:
(声明中没有缺省参数,定义给了也没用。)
综上所述:缺省参数以声明为准。
C++中的函数重载
在C语言中,不能出现名字相同的函数,因为C语言中的编译过程函数是通过函数名以及对应的地址来找到函数并调用的,如果名字相同,那么编译器将无法分辨是哪一个函数。而C++是使用修饰后的函数名字去查找所以C++是支持函数重载的。因为C++会根据类型和类型的个数或顺序 的不同来修饰函数名。
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这
些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型
不同的问题。
void fun(char a)
{
cout << "void fun(char a)" << endl;
}
void fun(int a)//参数类型不同
{
cout << "void fun(int a)" << endl;
}
void fun(int a,char c)//参数类型个数不同
{
cout << "void fun(int a,char c)" << endl;
}
void fun(char a,int c)//参数类型顺序不同
{
cout << "void fun(char a,int c)" << endl;
}
int main()
{
fun('b');
fun(2);
fun(1,'a');
fun('d', 1);
}
C++是无法重载仅按返回类型区分的函数的
如下:
C++中的引用
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空
间,它和它引用的变量共用同一块内存空间。
例如:
int main()
{
int a = 1;
int& b = a;//b c d 都是a 的别名
int& c = b;
int& d = a;
cout << a << " " << b << " " << c << " " << d << endl;
d++;
cout << a << " " << b << " " << c << " " << d << endl;
return 0;
}
引用在实际中的应用如下:
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int i = 5;
int b = -5;
swap(i, b);
cout << i << " " << b << endl;
return 0;
}
在C语言中,为了可以通过其他变量直接改变某一个变量的值由此引出了指针的概念,通过指针类型可以改变该指针指向的空间的内容。
在C++中,引用相当于为变量取一个别名(引用变量),这个别名和其对应的变量(引用实体)共用一个地址,所以可以通过引用直接改变对应的变量所在空间的内容。
所以本质上引用的底层依旧是指针实现。
int main()
{
int a = 0;
int* p = &a;//&既是引用符号 也是取地址符号具体得看你怎么用
int*& pf = p;//本来只有 p 指向a 的地址,pf 是 p 的别名 pf 也指向 a的地址
cout << "修改前" << endl;
cout << a << endl;
*pf = 1;
cout << "修改后" << endl;
cout << a << endl;
a = 0;
int& b = a;//此时 b是 a 的别名,修改b 就是修改 a
int& c = b;//c 是 b的别名 修改 c 等同于修改 b
cout << "修改前" << endl;
cout << a << endl;
c = 1;
cout << "修改后" << endl;
cout << a << endl;
return 0;
}
在C++中,引用有以下的特点:
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,就不能再引用其他实体(即不可以更改实体)
- 没有NULL引用
- 使用sizeof关键字计算某个引用的大小时,计算的是引用实体的类型大小,而不是一个固定值
- 引用变量自加1相当于对应实体内容加1
- 引用没有多级引用,即没有二级及以上引用
- 引用在访问指向的实体时不需要解引用,由编译器处理,除非实体是指针类型
- 引用在概念上没有实际地址
int main()
{
int a = 1;
const int& b = a;//权限可以缩小
cout << a << endl;
int m = b;//把 b 的值赋给了 m 所以没问题
int& i = a;// 缩小的是 b的权限跟 a没有什么关系,所以还是可以通过 i来修改a;
i = 10;
cout << a << endl;
const int c = 0;
//int& d = c;//这种写法是错误的,权限不能放大所以不能通过d 来修改c ;
const int& d = c;
return 0;
}
在指针/引用中,指针和引用的权限只可以缩小不可以放大 。
对比下面两幅图
int main()
{
int i = 10;
const int* pa = &i;
pa++;//因为 const 修饰的是 *pa 所以pa 是可以进行++ 的,但是打印的值是什么就不确定了
cout << *pa << endl;//-858993460
//下面属于是权限放大所以报错
int* p = pa;//"const int* " 类型的值不能用于初始化 "int*" 类型的实体
return 0;
}
可以以发现C语言中是可以运行并且修改的那是因为C语言的类型检查不严格。
感谢大家的观看!