📑 目录
- 一、namespace
- 1.1 namespace的价值
- 1.2 namespace的定义
- 1.3 命名空间的使用
- 二、C++输入&输出
- 三、缺省参数
- 四、函数重载
- 五、引用
- 5.1 引用的特性
- 5.2 引用的使用
- 5.3 指针与引用的关系
- 六、const引用
一、namespace
1.1 namespace的价值
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
// 编译报错:“rand”: 重定义;因为在头文件stdlib.h中rand是“函数名”
printf("%d\\n", rand);
return 0;
}
在一个项目中,命名冲突是很常见的问题,而namespace可以很好的解决
1.2 namespace的定义
- 定义命名空间需要用到关键字namespace,结构为namespace+空间名字+{ },{ }中为命名空间的成员 可以定义函数、变量等。
- namespace本质是定义一个域,这个域跟全局域各自独立 即不同的域可以定义同名变量。
- namespace只能定义在全局域,但可以嵌套定义
#include <stdio.h>
#include <stdlib.h>
namespace Tian{
int rand = 10;
//命名空间可以嵌套
namespace Li{ int rand = 20; };
namespace Nuo{ int rand = 30; };
}
int main(){
// 打印标准库rand函数的地址(函数要加&)
printf("%p\\n", &rand);
//这里访问指定命名空间的rand
printf("%d\\n", Tian::rand);//10
printf("%d\\n",Tian::Li::rand);//20
printf("%d\\n",Tian::Nuo::rand);//30
}
- 项目中多文件中同名namespace,被认为是一个namespace,不会冲突
- C++标准库都放在⼀个叫std(standard)的命名空间中。
1.3 命名空间的使用
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。可以通过以下三种方式去访问
#include<stdio.h>
namespace Tian{
int a=10;
}
int main{
//编译报错 a:未声明标识符
printf("%d\\n", a);
//指定命名空间访问
printf("%d\\n", Tian::a);
//using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式
using Tian::a;
printf("%d\\n", a);
//展开命名空间中全部成员(冲突⻛险很⼤)
using namespace Tian;
printf("%d\\n", a);
return 0;
}
二、C++输入&输出
- 是InputOutputStream的缩写,是标准的输入、输出流库,定义了标准的输入、输 出对象。
- cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要 通过命名空间的使用方式去用他们。
- std::cin 是istream类的对象,它主要⾯向窄字符(narrowcharacters(oftypechar))的标准输 入流。
- std::cout 是ostream类的对象,它主要⾯向窄字符的标准输出流。
- std::endl 是一个函数,流插⼊输出时,相当于插入⼀个换⾏字符加刷新缓冲区。
- <<是流插入运算符,>>是流提取运算符。(C语言还用这两个运算符做位运算左移/右移)。
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入 输出可以自动识别变量类型,C++的流能更好的支持自定义类型对象的输入输出。
- ⼀般日常练习中我们可以using namespace std,实际项目开发中不建议using namespace std
#include<iostream>
using namespace std;
int main(){
int a = 0;
double b = 0.1;
char c = 'x';
cout << a << " " << b << " " << c << endl;
// 可以⾃动识别变量的类型
cin >> a;
cin >> b >> c;
cout << a << endl;
cout << b << " " << c << endl;
return 0;
}
在io需求比较高的地方,如部分大量输入的竞赛题中,加上以下3行代码可以提高C++IO效率
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
三、缺省参数
- 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调用该函数时,如果没有指定实参 则采用该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数
- 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左 依次连续缺省,不能间隔跳跃给缺省值。
- 带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参。
- 做项目时函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
缺参使用示例
#include <iostream>
using namespace std;
void Func(int a = 0){
cout << a << endl;
}
int main(){
// 没有传参时,使⽤参数的默认值
Func(); //输出0
//传参时,使⽤指定的实参
Func(10); //输出10
return 0;
}
#include <iostream>
using namespace std;
// 全缺省
void Func1(int a = 10, int b = 20, int c = 30){
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
// 半缺省
void Func2(int a, int b = 10, int c = 20){
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
int main{
Func1(); //10+20+30 = 60
Func1(1); //1+20+30 = 51
Func1(1,2); //1+2+30 = 33
Func1(1,2,3);//1+2+3 = 6
Func2(100); //100+10+20 = 130
Func2(100, 200);//100+200+20 = 320
return 0;
}
四、函数重载
C++支持在同⼀作用域中出现同名函数,但是要求这些同名函数的形参不同(参数个数不同或者 类型不同)。这样C++函数调用就表现出了多态行为,使用更灵活。
#include<iostream>
using namespace std;
//参数类型不同
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;
}
//参数个数不同
void f(){
cout << "f()" << endl;
}
void f(int a){
cout << "f(int a)" << endl;
}
// 参数类型顺序不同
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;
}
// 返回值不同不能作为重载条件,因为调⽤时也⽆法区分
//void fxx()
//{}
//
//int fxx()
//{
//
return 0;
//}
// 下⾯两个函数构成重载
// 但是f1()调⽤时,会报错,存在歧义,既可以匹配无参的f1(),也能匹配带默认参数的f1(int a=10)(
//void f1(){
// cout << "f1()" << endl;
//}
//void f1(int a = 10){
// cout << "f1(int a)" << endl;
//}
五、引用
引⽤不是新定义⼀个变量,而是给已存在变量取了一个别名,编译器不会为引⽤变量开辟内存空间,它和它引⽤的变量共⽤同⼀块内存空间。比·如:李逵,江湖上人称"黑旋风";林冲,外号豹⼦头 类型& 引用别名=引用对象;
int main() {
int a = 0;
//bc都是a的别名
int& b = a;
int& c = b;
//也可以给别名b取别名,d相当于还是a的别名
int& d = b;
++d;//a++
return 0;
}
5.1 引用的特性
- 引用在定义时必须初始化
- 引用绑定的对象不能换
int a = 10;
int& b = a;
int c = 20;
b = c;
// 这⾥并⾮让b引⽤c,因为C++引⽤不能改变指向,
// 这⾥是⼀个赋值
cout << &a << endl;
cout << a << endl;
cout << &b << endl;
cout << &c << endl;
b、c引用的对象地址一样,即绑定对象一样 
5.2 引用的使用
引⽤在实践中主要是用·于引用传参和引用做返回值中减少拷贝提高效率和改变引⽤对象时同时g改变被引用对象。
用引用来实现交换函数,可以减少地址拷贝,语法更简洁
void Swap(int& rx, int& ry){
int tmp = rx;
rx = ry;
ry = tmp;
}
这里ret 是函数局部变量,函数运行结束后会销毁。 return ret 时:会把 ret 的值拷贝一份到临时变量,放到寄存器里,再把临时变量的值赋值给外面的x。 缺点:产生拷贝,大对象时开销大
int func()
{
int ret = 0;
return ret;
}
int x =func();
由此可以明白顺序表找下表的方法,是将数组对应下标的值拷贝到临时变量里返回,同时也无法修改这个临时变量的值,因为这个临时变量 是纯右值,语法规定右值不能作为赋值左操作数
int SLAt(SL& sl, int i)
{
return sl.a[i]; // 拷贝元素到临时变量,产生副本
}
SLAt(sl,i) += 1;//这个编译会报错,左操作数要是左值
修改后,return sl. a[i],可以理解为用一个临时引用变量 int& tmp = sl. a[i](编译器不会真的创建一个名叫 tmp 的变量,只是逻辑等价),返回的是返回对象的别名,这样就可以对数组的数进行修改
int& SLAt(SL& sl, int i)
{
return sl.a[i];
}
SLAt(sl,i) += 1;
注意:func()那里不能把返回值int变成int&,因为ret是函数局部变量,返回他的引用时,ret空间已经被销毁了,本质是一种类似野指针的行为
5.3 指针与引用的关系
C++中指针和引用在实践中他们相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代。
- 语法概念上:引用是⼀个变量的取别名,不开空间;而指针是存储⼀个变量地址,要开空间。
- 引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
- 引用在初始化时绑定一个对象后,就不能再绑定其他的对象了;而指针可以不断地改变指向对象。
- 引用可以直接访问指向对象,指针需要解引⽤才是访问指向对象。
- 指针容易出现空指针或者野指针,而引用一般不会,因此引用使用起来更安全一些。
- sizeof(引用):得到的是原数据类型本身的大小,但sizeof(指针)始终是地址空间所占字节个数(32位平台下占4byte,64位下是8byte)。
六、 const引用
- 在C++中对象的访问权限在引用过程中可以缩小,但是不能放大
const int a = 10; // a是常量,只读,不能修改
int& r1 = a; // 报错!普通引用会修改权限,权限放大,禁止
const int& r2 = a;// 合法,const引用只读,权限匹配
int b = 20; // b既可读,也可写
const int& r = b; // 合法,权限可以缩小
r = 100; // 报错:r是const引用,只读
b = 100; // 合法:原变量本身依旧能改
- int& rb = a*3; double d = 12 .34 ; int& rd = d ; a*3的结果保存在⼀个临时对象中,int& rd = d 也是类似,在类型转换中会产生临时对象存储中间值,也就是说 rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。
- 所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象
int a = 10;
const int& ra = 30;
//int& rb = a * 3; 编译报错,a*3的运算结果会用一个临时对象储存,不能用可修改普通引用int&绑定,因为权限不能放大
const int& rb = a*3;//const int& 常引用可以正常绑定
double d = 12.34;
// int& rd = d;编译出错,因为d 是 double 类型变量,引用 rd 是 int&,类型不匹配,编译器会自动隐式转换:把 12.34 截断小数,生成临时 int 值 12,这个 12 是匿名临时对象
const int& rd = d;
网硕互联帮助中心




评论前必须登录!
注册