文章目录
1C++入门
1-1匿名空间:
- ## 为了防止变量,函数,类的名称的的冲突,引入了匿名函数,对标识符的名字本地化
namespace bit
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
//比特就业课
struct Node
{
struct Node* next;
int val;
};
}
//2. 命名空间可以嵌套
// test.cpp
namespace N1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
// ps:一个工程中的test.h和上面test.cpp中两个N1会被合并成一个
// test.h
namespace N1
{
int Mul(int left, int right)
{
return left * right;
}
1-2:匿名空间的使用
namespace bit
{
inline int mul(int a, int b)
{
return a * b;
}
}
int main()
{
/*cout << Add(2, 3) << endl;
int a = 10;
int* b = &a;
auto&c = *b;
cout << c << endl;*/
cout << bit::mul(10, 20) << endl;
}
1-3输入输出
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
cout<<"Hello world!!!"<<endl;
return 0;
}
说明:
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件 以及按命名空间使用方法使用std。
- cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
- <<是流输入,>>是流输出
- count,cin是比较方便的,不需要像printf和scanf一样输入参数的类型
- cout,cin也涉及函数重载的问题,后面会有博客
#include <iostream>
using namespace std;
int main()
{
int a;
double b;
char c;
// 可以自动识别变量的类型
cin>>a;
cin>>b>>c;
cout<<a<<endl;
cout<<b<<" "<<c<<endl;
return 0;
}
// ps:关于cout和cin还有很多更复杂的用法,比如控制浮点数输出精度,控制整形输出进制格式等 等。因为C++兼容C语言的用法,这些又用得不是很多,我们这里就不展开学习了。后续如果有需要,我 们再配合文档学习。
std明名的习惯
std命名空间的使用惯例: std是C++标准库的命名空间,如何展开std使用更合理呢? 1. 在日常练习中,建议直接using namespace std即可,这样就很方便。 2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对 象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模 大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。
2-缺省参数
2-1半缺省参数
void time(int year=1, int month=1, int hour=1)
{
cout << year << " " << month << "" << hour << endl;
}
int main()
{
/*cout << Add(2, 3) << endl;
int a = 10;
int* b = &a;
auto&c = *b;
cout << c << endl;*/
//cout << bit::mul(10, 20) << endl;
time(1, 2);
}
言外之意就是缺省一部分的值
2-2:全缺省
void time(int year=1, int month=1, int hour=1)
{
cout << year << " " << month << "" << hour << endl;
}
int main()
{
/*cout << Add(2, 3) << endl;
int a = 10;
int* b = &a;
auto&c = *b;
cout << c << endl;*/
//cout << bit::mul(10, 20) << endl;
time();
}
全部都缺省的值
3:函数重载
3-1参数类型不同
void fun(int a, double b)
{
cout << a << " " << b << endl;
}
void fun(int a, int c)
{
cout << a << " " << c << endl;
}
int main()
{
int a = 1;
double b = 2.3;
int c = 0;
fun(a, b);
fun(a, c);
}
3-2:顺序不同
void fun(int a, double b)
{
cout << a << " " << b << endl;
}
void fun(double a,int b)
{
cout << a << " " << c << endl;
}
int main()
{
int a = 1;
double b = 2.3;
int c = 0;
fun(a, b);
fun(b,a);
}
3-3:个数不同
void fun(int a)
{
cout << a << " " << endl;
}
void fun(double a,int b)
{
cout << a << " " << b << endl;
}
int main()
{
int a = 1;
double b = 2.3;
int c = 0;
fun(a);
fun(b,a);
}
3-4:不同原因
一个程序运行要经历四个阶段:预处理,编译,汇编,链接
预处理主要是宏函数的替换,头文件的展开相应函数展开,条件替换,去掉注释…
编译主要检查语法问题
汇编主要生成相应的二进制码,将程序转换成二进制码
链接主要是链接可执行程序
void StackInit(struct Stack* ps,int x)
{
ps->a = (int*)malloc(sizeof(int) * 10);
ps->pos1 = 0;
}
void StackInit(struct Stack* ps,double x)
{
ps->s = (double*)malloc(sizeof(double) * 10);
ps->pos2 = 0;
}
void Stackpush(struct Stack* ps, int x)
{
assert(ps);
ps->a[ps->pos1++]=x;
cout << "int函数" << endl;
}
void Stackpush(struct Stack* ps, double x)
{
assert(ps);
ps->a[ps->pos2++] = x;
cout << "double函数" << endl;
}
int main()
{
struct Stack sl;
StackInit(&sl,1);
StackInit(&sl, 1.1);
Stackpush(&sl, 1);
Stackpush(&sl, 1.1);
}
链接的时候可以通过不同函数的地址调用函数,连接器通过第一个int类型的初始化和插入函数生成相应的init.o类型的程序没有找到,就会到double类型的符号表里面去找
3-4-1为什么能找到
函数名修饰规则不一样
4引用
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体
4-1:引用做参数
int swap(int&a,int&b)
{
int tmp = a;
a = b;
b = tmp
}
4-2:做返回值
int&count()
{
static int n;
n++;
return n;
}
4-3:常引用
int main() { /*struct Stack sl; StackInit(&sl,1); StackInit(&sl, 1.1); Stackpush(&sl, 1); Stackpush(&sl, 1.1);*/ const int a = 10; int& b = a; //权限的放大 double c = 10; int& m = c; //类型错误 }
要注意权限可以变小,平移,但是不能放大,类型不能有问题
4-4:引用优点
用数值作为返回值时候会生成拷贝,有空间和时间,但是引用就没有相关消耗。是对原来差数的引用
#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{
A a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
引用和返回值性能比较
4-5引用和指针的区别
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
int main()
{
int a = 10;
int& ra = a;
cout<<"&a = "<<&a<<endl;
cout<<"&ra = "<<&ra<<endl;
return 0;
}
在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
引用和指针的不同点:
1引用概念上定义一个变量的别名,指针存储一个变量地址。 2. 引用在定义时必须初始化,指针没有要求 3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体 4. 没有NULL引用,但有NULL指针 5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节) 比特就业课 6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小 7. 有多级指针,但是没有多级引用 8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理 9. 引用比指针使用起来相对更安全
5内联函数
5-1:特点
优点:用空间换时间节省了函数的调用
缺点:可能让调用的函数文件变大
一般不建议把递归并且经常调用的函数作为内联
内联函数的定义和声明不能分开分开后导致内联函数展开找不到地址
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{
f(10);
return 0;
}
这个代码会报错
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 “void __cdecl f(int)” (?f@@YAXH@Z),该符号在函数 _main 中被引用
面试问宏函数的优点:
代码复用性能好
提高性能
面试问宏函数的缺点
1,不好调试
2可维护性差,可读性能差,容易吴勇
3没有安全的类型检查
C++有哪些替代宏函数
常量用const enum
简短的函数用inline内联函数
6auto函数
1函数的调用数组的时候不能用auto
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <<endl;
}
// main.cpp
#include "F.h"
int main()
{
f(10);
return 0;
}
这个代码会报错
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用
面试问宏函数的优点:
代码复用性能好
提高性能
面试问宏函数的缺点
1,不好调试
2可维护性差,可读性能差,容易吴勇
3没有安全的类型检查
C++有哪些替代宏函数
常量用const enum
简短的函数用inline内联函数
6auto函数
1函数的调用数组的时候不能用auto
```c++
void TestFor(int array[])
{
for(auto& e : array)
cout<< e <<endl;
}
不知道end,不能确定范围1