[C.C++] 【C++】入门基础

425 0
Honkers 2025-6-18 12:28:28 来自手机 | 显示全部楼层 |阅读模式

💒前言

  学习本章内容需要掌握C语言{类型、循环、函数、结构体、指针}等内容 建议学完C再看
  希望对从来没有接触过C++ 只是听过的小白 有些帮助
  ——我并不专业,也是正在学习C++的小学生!

🧸什么是C++

  C++是C升级而来,所以C++程序兼容C的大部分代码!

🧸初识C++代码

先看一段C的代码

  1. #include <stdio.h>
  2. int main()
  3. {
  4. printf("hello world!");
  5. }
复制代码

  这段代码很简单,#include 是printf函数的头文件,包含头文件,printf打印函数才可以在屏幕上打印;
  并且打印其他类型需要自己指定例如:
  int a = 10;
  printf("%d\n",a);
下面是C++的代码

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. cout <<"hello world!"<< endl;//流插入
  6. return 0;
  7. }
复制代码

  解释以下上面的代码,
  #include 是C++的库,io意为输入输出;stream意为流。
                        ——————可以称之为 输入输出流
  using namespace std;要解释这句 ,你需要先知道命名空间这个功能,下面会讲

  cout <<"hello world!"<< endl; ,cout:流插入;endl:换行符;

  此句意为 将"hello world!"字符串流向cout ,也就打印在了屏幕上,后面是将 endl 流向cout; 后面会详解

🧸命名空间

  关键字:namespace
  命名空间:可以理解为 变量、函数 的名字的作用域
  在C++的库中 都是将函数的实现 封装起来 为了防止命名冲突
用法

  1. namespace N
  2. {
  3. int a = 10;
  4. int Add(int left, int right)
  5. {
  6. return left + right;
  7. }
  8. }
  9. int main()
  10. {
  11. printf("%d\n", a); // 该语句编译出错,无法识别a
  12. return 0;
  13. }
复制代码

  上述代码 是无法识别到a的,因为a 不在main函数中,也不再全局变量中,而是封装在N的命名空间中
  main函数找a的顺序:先找局部,再找全局
如何找到a
  :: 作用域运算符
  在a前面加上命名空间 N和作用域运算符::

  1. int main()
  2. {
  3. printf("%d\n", N::a);
  4. }
复制代码

展开命名空间
  关键字:using
  展开后 命名空间失效 ,内部代码全部暴露
  此时可以解释using namespace std;是什么意思
  展开名字叫std的命名空间,因为不展开 所有的对象都用不了

也可以展开部分对象
  using std::cin; //展开cin - 流提取,接收变量的 与scanf作用相同
  using std::cout; //展开cout - 流插入 ,打印变量的 与printf作用相同
cout、cin是一个ostream类的对象

对象
  类似C中的结构体,在C++中叫对象

🧸输入、输出

你可以复制这段代码 测试一下

  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int a;
  6. cin>>a;
  7. cout<<a<<endl;
  8. return 0;
  9. }
  10. 输入 a 的数值,并打印 ,在c++中打印会自动识别类型
复制代码

🧸缺省参数

  在定义函数时 可以提前给定数值,传参时可以少传参数、或者不传参数

  1. void TestFunc(int a = 0)
  2. {
  3. cout<<a<<endl;
  4. }
  5. int main()
  6. {
  7. TestFunc(); // 没有传参时,使用参数的默认值
  8. TestFunc(10); // 传参时,使用指定的实参
  9. }
复制代码

全缺省:多个函数参数 都有缺省参数

  1. void TestFunc(int a = 10, int b = 20, int c = 30)
复制代码

半缺省:从右向左依次给缺省参数

  1. void TestFunc(int a, int b = 10, int c = 20)
复制代码

缺省参数不能在函数声明和定义中同时出现

问题: 如果是以下程序 会如何调用?

  1. void Test(int a = 0)
  2. {
  3. cout << a << endl;
  4. }
  5. void Test()
  6. {
  7. cout << 10 << endl;
  8. }
  9. int main()
  10. {
  11. Test();
  12. return 0;
  13. }
复制代码

  上述代码中出现了两个Test,构成函数重载,在C中不支持,在C++中支持 ,函数重载则可以解释
  先说结论:报错 Test 对重载函数的调用不明确
  如果没看懂,先看下面的,再回来看。

🧸函数重载

  同意作用域 可以有多个重名函数,条件是:参数个数、类型、顺序,必须不同
  返回类型 不同 不构成函数重载

  1. void Test(double a)
  2. {
  3. cout << a << endl;
  4. }
  5. void Test(int a)
  6. {
  7. cout << a << endl;
  8. }
  9. int main()
  10. {
  11. Test(1.1);
  12. Test(1);
  13. return 0;
  14. }
复制代码

  上述代码,会根据给定的实参去找对应的函数,复制代码试一试
原理
  C不支持函数重载是因为C语言对函数的命名规则比较简单


  C++在Windows下的规则过于复杂,不便观看,下面用linux演示

  1. int Add(int a,double b,int* p)
复制代码

  对于以上代码 C的汇编 函数名Add
  C++的汇编函数名 _Z3AddidPi
    _Z 前缀
    3 函数名个数
    Add 函数名
    i int类型
    d double类型
    Pi int*类型

回顾编译器,编译的过程
  1、预处理:头文件展开、宏替换、条件编译、去掉注释,生成.i文件
  2、编译:检查语法、生成汇编代码,生成.s文件
  3、汇编:汇编代码转换成二进制机器码 ,生成.o文件
  4、链接:生成.out文件
  如果文件中有 函数的实现 则函数产生的名字 直接带有汇编实现地址
  如果文件中只有函数声明,定义在顶一个cpp文件中,则连接的时候,到.o生成的符号表里找到函数的定义的地址,才会填写函数的地址

🧸引用

  引用符号:&
  引用:变量的别名
  用法:Type& name;
引用概念
  例如:一只修勾叫多多,它原来叫 狗狗 ,起了个名字 叫多多,本质上 都是同一只修勾!

  1. void TestRef()
  2. {
  3. int a = 10;
  4. int& b = a;//<====定义引用类型
  5. printf("%p\n", &a);
  6. printf("%p\n", &b);
  7. }
复制代码


  可以看到 a和b的地址相同 值相同,证明b就是a,那有什么用呢? 后面详解。
引用特性
  1、必须初始化 int& b; 这样写是不对的
  2、一个变量可以有多个引用,int a ; int &b = a; int& c = b; int& d = a;可以同时存在
  3、引用只能引用一个实体 int a; int c ; int & b = a; 这样没问题 在写一个int& b = c;则错误,不能改变。

引用使用场景
  1、做参数 :a.提高效率 b.形参修改,改变实参

  1. void Swap(int& left, int& right)
  2. {
  3. int temp = left;
  4. left = right;
  5. right = temp;
  6. }
  7. 此时,形参改变会影响 实参,因为形参是实参的引用,实际上就是实参,而且不会产生临时变量。
复制代码

  2、做返回值 :a.提高效率 b.修改返回变量
  提高效率 是因为,不管事传值,还是传址,都会产生临时变量而拷贝,而引用则不会产生临时拷贝,从而减少工作量

  1. #include N 10;
  2. int& At(int i)
  3. {
  4. static int a(N);
  5. return a[i];
  6. }
  7. for(size_t i = 0;i<N;i++)
  8. {
  9. At(i) = 10+i;
  10. }
复制代码

  加上关键字static,该变量就被定义成为一个静态全局变量
  此时a是静态变量 不会被销毁 而且返回值是 左值 可以被修改 反回了a这个空间的别名

  当函数返回值 出了函数作用域销毁 则不能使用引用做返回值

  1. int& Add(int a,int b )
  2. {
  3. int ret = a+b;
  4. return ret;
  5. }
复制代码

  此时 函数调用完ret会被回收,可能会造成非法访问

引用权限

  1. 权限放大 - 不行
  2. const int a = 10;
  3. int& b = a;
  4. 权限不变 - 可以
  5. const int c = 20;
  6. consr int& d = c;
  7. 权限缩小 - 可以
  8. int e = 30;
  9. const int& f = e;
  10. `注:`表达式产生的结果是 具有常属性的 所以想要引用则需要加const
  11. int x1 = 1, x2 = 2;
  12. const int& y = x1+x2; 可以
  13. 包括整形提升、截断 所产生的的是 临时拷贝的整形提升、截断
  14. double d = 11.11;
  15. int a = d;
  16. a = 11 是 d 的临时拷贝 进行截断产生的
  17. int& i2 = d; 不可以 - 因为临时拷贝有常属性不能改变
  18. const int& i3 = d; 可以 用const修饰后 i3则不能改变 权限不变
复制代码

引用和指针的区别

  在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
  在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

Col1引用(渣男)指针(专一)
意义存变量的地址是变量的别名
初始化不一定要初始化必须初始化
能随意指向同类型实体只能引用一个实体
空值有NULL指针没有NULL引用
大小指针大小固定引用的大小是实体的大小
增加指针增加是偏移一个类型的大小引用增加是实体+1

  总结:指针使用更为复杂 因为控制不好可能会出现野指针 空指针 ,所以没有引用安全

🧸extern “C” 编译连接C++与C的调用

  例如:
    1、C调用C++写的库(静态库、动态库)
    2、C++调用C写的库(静态库、动态库)
    实现方法待填写

🧸内联函数 inline

  1. 在C中为了 减少函数调用可以使用宏
  2. #define ADD(x,y) ((x)+(y))
  3. 来代替 ADD(int x, int y){return x+y;}
  4. 但是宏很复杂 例如控制不好括号 容易造成错误
  5. 有了inline 则可以代替宏
  6. inline void Func()
  7. {
  8. .假设编译后是10行代码
  9. }
复制代码

内联函数原理
  可以减少函数栈帧,直接替换成代码 不建立栈帧
内联函数使用场景
  建议 代码长度小于10 或20行 而且经常调用的函数

  危害:
    1、假设内联函数展开是10行 调用1000次 则是10*1000 = 10000行代码
    2、假设函数不展开 调用1000次 则是10+1000 = 1010行代码
内联函数结论
  短小,频繁调用的函数建议定义成inline

🧸auto 自动填写类型

  auto在类型特别长的时候用起来很好,或者在下面的范围for循环中可以用

  1. int a = 0;
  2. auto b = a;
  3. auto c = 'c';
  4. auto d = 1.1;
复制代码

🧸基于范围的for循环(C++11)

在C中循环这样写

  1. int main()
  2. {
  3. int a[] = {1,2,3,4,5,6,7,8,9};
  4. int n = sizeof(a) / sizeof(a[0]);
  5. for(int i = 0;i < n ;i++)
  6. {
  7. printf("%d ",a[i]);
  8. }
  9. return 0;
  10. }
复制代码

在C++中的范围for这样写

  1. int main()
  2. {
  3. int a[] = {1,2,3,4,5,6,7,8,9};
  4. for(auto i:a)
  5. {
  6. cout << i <<" ";
  7. }
  8. cout << endl;
  9. return 0;
  10. }
复制代码

  运行结果如下


  这里 auto 可以自动识别 i的类型 ,当然自己写int也可以

范围for赋值呢?

  1. int main()
  2. {
  3. int a[] = { 1,2,3,4,5,6,7,8,9 };
  4. for (auto& i : a)
  5. {
  6. i = 10 + i;
  7. }
  8. for (auto i : a)
  9. {
  10. cout << i << " ";
  11. }
  12. cout << endl;
  13. return 0;
  14. }
复制代码

  给i添加个引用符号 ,让i等于a[] 中的元素,直接改变i即可!
范围for使用条件
  下列代码错误,因为不确定a的范围

  1. void TestFor(int array[])
  2. {
  3. for(auto& e : array)
  4. cout<< e <<endl;
  5. }
复制代码

🧸空指针nullptr(c++11)

  在C中空指针是 NULL 而NULL本质 = 0;而这样在C++中可能会产生歧义

  1. void f(int)
  2. {
  3. cout<<"f(int)"<<endl;
  4. }
  5. void f(int*)
  6. {
  7. cout<<"f(int*)"<<endl;
  8. }
  9. int main()
  10. {
  11. f(0);
  12. f(NULL);
  13. f((int*)NULL);
  14. return 0;
  15. }
  16. 结果为:f(int)
  17. f(int)
  18. f(int*)
  19. 也就是NULL 也去调用了第一个f(int),而没有调用f(NULL)
复制代码

  cout << sizeof(nullptr) << endl;
  cout << sizeof(void*) << endl;
  结果都为4

后续使用都推荐nullptr

🎀结束

  本次的入门基础 就结束啦 ,下一章 类和对象!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4014
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行