快速导航
0.用C++输出 hello world!
学习任何一门编程语言,最先掌握的就是使用这门语言来写一个 hello world! :
#include <iostream>
using namespace std;
int main()
{
cout << "helo world!" << endl;
return 0;
}
至于为什么这样写,就需要了解下面这些C++的入门知识了。
1.命名空间
using namespace std; //std是C++的标准库所在的命名空间,这句话就是把C++标准库中的内容进行展开
C++标准库中的内容比较多,可能带来一些负面的印象,所以我们可以写一个不展开std 版本的hello world ! 。
#include <iostream>
int main()
{
std::cout << "helo world!" << std::endl;//只使用std中的cout和endl
return 0;
}
在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称如果都存在于全局作用域中,可能会导致冲突。
像下面这段代码(编译的时候会报错):
#include <iostream>
#include <stdlib.h>
int rand = 10;
int main()
{
printf("%d\n", rand);
return 0;
}
rand函数和rand变量都在全局域中,打印的时候会产生冲突; 而使用命名空间就是对名称进行作用域限制,以避免名称冲突。
1.1命名空间的定义
namespace name { }
使用命名空间可以对以上代码进行改善:
#include <iostream>
#include <stdlib.h>
namespace zwx
{
int rand = 10;
}
int main()
{
printf("%d\n", zwx::rand);
return 0;
}
1.2命名空间的分类
普通的命名空间
namespace N1 // N1为命名空间的名称
{
// 命名空间中的内容,既可以定义变量,也可以定义函数
int a;
int Add(int left, int right)
{
return left + right;
}
}
嵌套的命名空间
namespace N2
{
int a;
namespace N3
{
int c;
}
}
1.3命名空间的三种使用方式
假如存在这样一个命名空间需要使用:
namespace N
{
int a = 10;
}
1.域作用限定符
int main()
{
printf("%d\n", N::a);
return 0;
}
2.使用using将命名空间的成员引入
using N::a;
int main()
{
printf("%d\n", a);
return 0;
}
3.使用using namespace将命名空间的名称引入
using namespace N;
int main()
{
printf("%d\n", N::a);
return 0;
}
2.C++中的输入&输出
使用C++输入、输出更方便,不需要增加数据格式的控制。
#include<iostream>
using namespace std;
int main()
{
int a;
double b;
cin >> a;
cin >> b;
cout << a << b << endl;
return 0;
}
3.缺省参数
3.1缺省参数的概念
通俗来讲就是:在函数调用时,没有传实参而使用的默认值。
void func(int a = 10)
{
cout << a << endl;
}
int main()
{
func();
return 0;
}
3.2缺省参数的两种分类
全缺省参数:
void func(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
注意:全缺省中实参传递时是从左往右进行传递的,而不能进行间隔传参。
如图所示,这种传参方式在C++中是不允许的。
半缺省参数:
void func(int a, int b = 10, int c = 20)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
注意:半缺省参数必须从右往左依次给出,不能间隔着给出。
3.3缺省参数在声明和定义中的异同
缺省参数有一个硬性要求:不能在声明和定义中同时存在。
创建两个文件stack.h和stack.cpp,其中在stack.h中放函数stack_init的声明,在stack.cpp中放函数定义。
//stack.h
struct stack
{
int* a;
int top;
int capacity;
};
void stack_init(struct stack* ps, int capacity = 100);//声明
//stack.cpp
#include "stack.h"
void stack_init(struct stack* ps, int capacity = 200)
{
ps->capacity = capacity;
ps->a = (int*)malloc(sizeof(int) * capacity);
ps->top = 0;
}
缺省参数在声明和定义中有三种情况:
1.声明和定义中同时存在:
2.声明中给缺省值:
传参的时候可以不传capacity,默认给的值就是声明中capacity的缺省值。
3.定义中给缺省值:
定义时由缺省值,声明中没有;这种情况下在传参的时候需要传入capacity,否则会报错,传入capacity的话初始化的时候使用的就是传入的值,定义中的缺省值没有意义。
4.函数重载
4.1函数重载的使用
C语言是不支持相同函数名的函数的,也就是不支持函数重载,C++中函数重载的出现简化了很多问题。
C语言中要实现两个变量的交换,不同的类型不能使用相同的函数名,所以在C语言中完成两个int 类型变量的交换、两个double类型变量的交换,只能这样去完成:
void swapi(int *p1, int *p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void swapd(double *p1, double *p2)
{
double tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10, b = 20;
double c = 1.1, d = 2.2;
swapi(&a, &b);
swapd(&c, &d);
return 0;
}
C++中支持的函数重载,功能相同,类型不同时可以使用相同的函数名:
#include <iostream>
using namespace std;
void swap(int *p1, int *p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void swap(double *p1, double *p2)
{
double tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10, b = 20;
double c = 1.1, d = 2.2;
swap(&a, &b);
swap(&c, &d);
return 0;
}
参数的不同类型会调用不同的函数(调用的时候很像是同一个函数,实际上调用的并不是同一个函数)。
4.2能够构成函数重载的三种情况
- 参数个数不同
- 参数类型不同
- 参数顺序不同
参数个数不同和参数类型不同都很容易理解,下面来谈一谈顺序不同的情况:
#include <iostream>
using namespace std;
void func(int a, char ch){}
void func(char ch, int a){}
int main()
{
int a = 10;
char ch = 'c';
func(a, ch);
func(ch, a);
return 0;
}
上述代码中,传入的两个参数都是一个为int类型 , 一个为char 类型,但是一个是先传int 类型参数,一个是最后传int 类型参数;
顺序不同,构成函数重载。
5.引用
5.1引用的概念
通俗来讲,引用就是给一个变量起别名;像水浒传中的李逵,也叫黑旋风,李逵和黑旋风是同一个人。
int a = 10;
int& b = a;//b是a的别名,指向的是同一块空间
注意:引用在定义的时候必须初始化
错误样例:
int a = 10;
int& b;
b = a;
5.2引用的使用
- 函数形参
- 函数返回值
使用引用作函数的形参同样使用swap函数为例:
void swap(int& m, int& n) //m是a的别名,n是b的别名
{
int tmp = m;
m = n;
n = tmp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
return 0;
}
swap函数中传入的参数m和n,其实就是a和b的别名,对m和n进行操作也就是对a和b进行操作,所以能够完成a和b的交换。
swap函数中只有两个变量,拷贝不拷贝对效率影响不大,但是如果有大量的数据进行传参的时候,传引用的效率会更高,因为传引用的时候不会发生拷贝。
传引用返回
传引用返回是有前提条件:出了函数作用域,返回对象不销毁。
举个例子:
int count()
{
int n = 0;
n++;
return n;
}
int main()
{
int ret = count();
return 0;
}
像这种情况就不能使用引用返回,n变量在count函数的栈帧中,出了count函数,n会自动销毁。
上述代码想要使用引用返回,可以对其进行修改:
int& count()
{
static int n = 0;
n++;
return n;
}
int main()
{
int ret = count();
return 0;
}
给count函数中的n加上static修饰,n就存储在了静态区,出了count函数静态去中的变量依然存在,可以使用引用返回。
5.3引用的使用场景
给定一个C语言版本的顺序表初始化:
typedef struct SeqList
{
SLDataType* a; // 指向动态数组指针
int size; // 数据个数
int capacity; // 容量-空间大小
}SL;
void SLInit(SL* ps)
{
assert(ps != NULL);
ps->a = NULL;
ps->size = ps->capacity = 0;
}
int main()
{
SL sl;
SLInit(&sl);
return 0;
}
现在用C++中的引用代替指针:
void SLInit(SL& ps)
{
assert(ps != NULL);
ps.a = NULL;
ps.size = ps.capacity = 0;
}
int main()
{
SL sl;
SLInit(sl);
return 0;
}
使用引用代替指针,可以使我们写的代码更简洁,而且更容易理解;使用引用作函数的返回值可以实现指针不能达到的效果。
快速入门C++的内容,到这里就结束了,觉得有所收获的话,记得点赞+收藏+关注,感谢支持!