从今天这篇博客起,我想从我所掌握的角度,逐渐向大家介绍C++的初阶知识。
一、关于std
std::是个名称空间标识符,C++标准库中的函数或者对象都是在命名空间std中定义的,所以我们要使用标准库中的函数或者对象都要用std来限定。
比如我们要使用标准库中的cout,直接调用是不行的。下面有三种方法来帮助我们调用:
plan1: 指定命名空间(在函数前面加上标准库名),即每使用一次,都在前面加上std:: 特点:是最规范的写法,但是麻烦
int main()
{
std::cout << "hello world" << std::endl;
std::vector<int> v;
std::string s;
return 0;
}
plan2: 把std整个展开(相当于将整个标准库都引进了我们的全局空间) 缺陷:如果我们自己定义的东西跟库里原有的东西冲突了就没办法解决了
一般规范的工程项目中不推荐这种方式
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
plan3:(介于上面两种方式之间) 对部分库中常用的东西展开, 其余在用的时候在前头加上std:: 注意只能一行一行写 usingstd::cout; using std::endl;
using std::cout;
using std::endl;
int main()
{
cout << "hello world" << endl;
std::string s;
return 0;
}
以上三种方法,对于自己定义的命名空间也可以使用
另外,在C语言中,::变量还有另一种作用:表示全局域
int a = 0;
int main()
{
int a = 1;
printf("%d\n", a);//1 局部优先原则
printf("%d\n", ::a);//0
return 0;
}
二、C++中的输入(cin)与输出(cout)
这里主要先讲用法,背后的原理暂且不讲,因为涉及到其他知识
cout - 本质上是ostream这个类的全局对象
cin - 本质上是istream类的全局对象
头文件:#include
#include
int main()
{
cout << "hello world";
//endl是换行符,可加可不加
//若想换行后再空一行,则:
cout << "hello world" << endl << endl;
//好处:可以自动识别类型,printf需要手动输入打印的类型
int a = 0;
cin >> a;//cin也可以自动识别类型
return 0;
}
三、缺省参数
含义:
声明函数时,为函数的参数指定一个默认值,若没有指定实参则采用该默认值
注意点:
(1)必须是从右往左缺省
(2)缺省值必须是常量或者是全局变量
缺省分为全缺省和半缺省:
(1)全缺省
void TestFunc(int a = 10, int b = 20, int c = 30);
(2)半缺省
原则:必须是从右往左缺省(缺省 = 给默认值,因为实参是从左往右给的),并且是连续的
void Testfunc(int a, int b = 10, int c = 20);//对
void Testfunc(int a = 10, int b = 20, int c);//错
注意:半缺省至少要传一个参数
半缺省在调用时更加灵活
实际应用举例:
struct stack
{
int* a;
int size;
int capacity;
};
void stackInit(struct stack* pa, int Initcapacity = 10)
{
pa->a = (int*)malloc(sizeof(int) * Initcapacity);
pa->size = 0;
pa->capacity = Initcapacity;
}
int main()
{
//假设事先知道s1里面至少要存放100个数据
struct stack s1;
stackInit(&s1, 100);
//假设事先知道s2里面最少要存放10个数据
struct stack s2;
stackInit(&s2);
return 0;
}
//这样可以根据不同的需要,是初始化时开辟的空间不同,不至于一棍子打死,也不至于浪费空间
四、函数重载
含义:根据参数类型不同,个数不同以及顺序不同而命名的同名函数(不包括返回值)
本质上是几个不同的函数
注意:
但注意:两个同名函数参数类型、参数个数、参数顺序相同,一个有默认参数一个没有,不算重载函数
(1)int Add(int a, int b);
(2)int Add(double a, double b);
(3)int Add(int a = 10, int b = 20);
(4)int Add(int a, int b);
(5)double Add(int a, int b);
(1)(2)是重载
(1)(3)不是重载
(4)(5)不是重载
在实际运用中,缺省参数和函数重载尽量不要一起使用。因为与可能出现二义性错误
例:
void f(int a, int b, int c = 1)
void f(int a, int b)
int main()
{
f(1, 2, 3);//调用第一个
f(1, 2);//error! 调用不明确(函数重载没有问题)
return 0;
}
五、引用
本质是取别名、取外号
定义方式:
int main()
{
int a = 0;
//b是a的别名,即b是a的引用
int& b = a;
b = 20;//此时a和b的值一起被改变
//是否可以继续对b取引用? 可以
int& c = b;
//此时abc共用同一块空间
//注意也可以对同一个变量取多个引用
return 0;
}
具体运用:
在C语言的交换函数中,我们传变量的地址
在C++中还可以传引用
void swap_by_yinyong(int& a, int& b)
{
int c = 0;
c = a;
a = b;
b = c;
}
int main()
{
int a = 1;
int b = 2;
swap_by_yinyong(a, b);
cout << a << b << endl;
return 0;
}
&在变量前面表示取地址,在类型(如int)后面才表示引用。
所以通过引用交换时,传的是a和b而不是&a和&b
引用的特点:
(1)引用和变量共用同一块内存空间
(2)引用必须在定义时初始化
(3)已定义的引用不能改变指代的对象
int& r = a;
int x = 10;
r = x;//不是将r变为x的别名,而是将x的值赋给r(a) r只能是a的引用
(4)一个变量可以有多个引用
·常引用
运用常引用时,记住一个原则:权限可以缩小,但权限不能放大!
const int a = 10;
int& ra = a;//属于权限放大 error!
//但是如果改为:
const int a = 10;
const int& ra = a;//正确 想要成为常变量的引用,必须用const修饰的常引用
//另外,
int b = 10;
const int& rb = b;//属于权限缩小 正确,此时不能再通过rb改变值
//但是还是可以通过b修改值,因为b本身不是const
使用常引用时还有一个非常容易出错的点:
还有。虽然在C语言中
int c = 10;
double d = 1.11;
d = c;
是被允许的,有强制类型转换
但是在C++中这么写是错误的:
int c = 10;
double& rc = c;//error!
double& rd = (double)c;//error! 强转转变的不是c的类型,是c的临时变量的类型
从语法上解释,rc此时是c的double类型的临时变量的引用,临时变量具有常量性
因此可以改作:
int c = 10;
const double& rc = c;
总结:C++中用到类型转换时,引用的前面要加上const
·引用的作用
(1)做参数
void swap(int& left, int& right)
(2)做返回值
int& Add(int a, int b)
{
int c = a + b
return c;//此时返回的是c的引用
}
int main()
{
int& ret = Add(1, 2);
return 0;
}
作返回值时,有两个注意点:
(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;//output:7
return 0;
}
出函数作用域时,如果变量未还给操作系统,则可以返回引用
若已还给操作系统,只能返回值,不能返回引用