1.命名空间
- 如我们所知,命名空间namespace的作用:namespace就是自己创建一个区域避免命名冲突或者名字污染
1.1命名空间的定义
- 命名空间只需要在namespace关键字之后输入定义的空间的名字,并在之后加上一对{}就行了
- 命名空间本质上就是创建一个作用域,用名字将其命名,和全局域别的域互相独立,互不影响
- 不同于局部域和全局域的是,局部和全局域是影响变量生命周期的,而命名空间和类域一样是不影响的
1.2命名空间的使用
- 使用命名的空间,指定访问,在项目中比较适用
- 展开命名空间的某一成员,针对某个变量多次出现
- 展开命名空间所有变量,冲突风险很大,更适用于日常练习
include<iostream>
namespace project1
{
int a = 0;
int b = 0;
}
//指定命名空间访问
int main()
{
cout<<project1::a<<endl;
return 0;
}
//展开某个成员访问
using project1::a
int main()
{
cout<<a<<endl;
return 0;
}
//全部展开
using namespace project1
int main()
{
cout<<a<<b<<endl;
return 0;
}
2.C++输入&输出
- iostream是标准输入和输出流库的使用对象
- std::cin 是 input stream的对象,主要面对窄字符的输入
- std::cout 是 output stream 的对象,主要面向窄字符的标准输出
- <<是流插入运算符,>>是流提取运算符
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
int main()
{
int a = 0;
double b = 0.1;
char c = 'x';
cout << a << " " << b << " " << c << endl;
std::cout << a << " " << b << " " << c << std::endl;
scanf("%d%lf", &a, &b);
printf("%d %lf\n", a, b);
// 可以⾃动识别变量的类型
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);
3.缺省参数
缺省参数用通俗易懂的话来讲就是,一个函数的形参的默认参数值,如果没有给参数,那么就用缺省参数,如果给了则忽略。分为全缺省和半缺省,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。
函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省
值。
include<stdio.h>
int Add(int x=1,int y=2);
int Add(int x,int y)
{
return x+y;
}
int main()
{
cout<<Add()<<endl;//结果为3
return 0;
}
4.函数重载
要满足函数重载要有那么几个条件
- 参数类型不同
- 参数个数不同
- 参数顺序不同
达成其一就是函数重载
#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;
// 返回值不同不能作为重载条件,因为调⽤时也⽆法区分
//void fxx()
//{}
//
//int fxx()
//{
// return 0;
//}
// 下⾯两个函数构成重载
// f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁
void f1()
{
cout << "f()" << endl;
}
void f1(int a = 10)
{
cout << "f(int a)" << endl;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}
5.引用
引用用最简单的话来说就是起别名,格式为
类型& 引⽤别名 = 引⽤对象;
注意事项:
•
引⽤在定义时必须初始化
•
⼀个变量可以有多个引⽤
•
引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体
引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被
引⽤对象,主要用于函数形参或者返回值
void Swap(int& rx, int& ry)
{
int tmp = rx;
rx = ry;
ry = tmp;
}
int main()
{
int x = 0, y = 1;
cout << x <<" " << y << endl;
Swap(x, y);
cout << x << " " << y << endl;
return 0;
}
typedef struct ListNode
{
int val;
struct ListNode* next;
}LTNode, *PNode;
// 指针变量也可以取别名,这⾥LTNode*& phead就是给指针变量取别名
// 这样就不需要⽤⼆级指针了,相对⽽⾔简化了程序
//void ListPushBack(LTNode** phead, int x)
//void ListPushBack(LTNode*& phead, int x)
void ListPushBack(PNode& phead, int x)
const引用 :
const引用的值不可以被修改,对于有常性的变量来说,或者存在隐式转换形成临时变量的,都用const 引用
double a = 1.1;
int b =2;
int c = 1;
const int& ra = a;
const int& d = (b+c);
C++中指针和引⽤就像两个性格迥异的亲兄弟,指针是哥哥,引⽤是弟弟,在实践中他们相辅相成,功
能有重叠性,但是各有⾃⼰的特点,互相不可替代。
•
语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
•
引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
•
引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。
•
引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。
•
sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下
占4个字节,64位下是8byte)
•
指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。
5.inline
用inline修饰的函数叫做内联函数,可以不用建立栈,提高效率。
任何在类的说明部分定义的函数都会被自动的认为是内联函数
在函数代码少且频繁调用的情况下适宜采用 inline 定义内联函数
#include<iostream>
using namespace std;
inline int Add(int x, int y)
{
int ret = x + y;
ret += 1;
ret += 1;
ret += 1;
return ret;
}
int main()
{
// 可以通过汇编观察程序是否展开
// 有call Add语句就是没有展开,没有就是展开了
int ret = Add(1, 2);
cout << Add(1, 2) * 5 << endl;
return 0;
}
本是设计用来代替宏函数的
//
实现⼀个
ADD
宏函数的常⻅问题
//#define ADD(int a, int b) return a + b;
//#define ADD(a, b) a + b;
//#define ADD(a, b) (a + b)
//
正确的宏实现
#define ADD(a, b) ((a) + (b))
//
为什么不能加分号
? 因为替换的话会把分号也替换上
//
为什么要加外⾯的括号
?遇到Add(1,5)*5 就会变成1+5*5,优先级不正确
//
为什么要加⾥⾯的括号
?遇到Add(1%2+5|3)就会变成1%7|3,优先级不正确
6.Nullptr
原null的值为常量0,并不能转换成其他类型的指针
C++11中引⼊nullptr,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字⾯量,它可以转换
成任意其他类型的指针类型。使⽤nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被
隐式地转换为指针类型,⽽不能被转换为整数类型。
#include<iostream>
using namespace std;
void f(int x)
{
cout << "f(int x)" << endl;
}
void f(int* ptr)
{
cout << "f(int* ptr)" << endl;
}
int main()
{
f(0);
//本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(int x),因此
//与程序的初衷相悖
f(NULL);
f((int*)NULL);
// 编译报错:error C2665: “f”: 2 个重载中没有⼀个可以转换所有参数类型
// f((void*)NULL);
f(nullptr);
return 0;
}