从零开始学 C++|系列开篇:从 C 到 C++ 的衔接之路

前言

之前在更新C语言的博客,学校C++课程这学期已经开始了,当然,我在3月3号已经提前练习了基础代码Luminous/Luminousbegin,下面我也要开始更新C++的博客了,请大家多多支持。

这既是给自己的学习留个脚印,也希望能帮到和我一样,刚学完 C 语言、正在跟着学校课程入坑 C++ 的同学。

一、为什么我跟着学校课学,还要自己写练习?

这学期学校正式开了 C++ 程序设计课,但我发现:

  • 学校课上的例子比较简单,光听不写很容易忘,必须自己动手敲一遍才能真正理解
  • 最重要的是:我发现C++ 的核心其实就是 C 语言的升级版,之前写 C 语言通讯录、顺序表、链表打下的基础,完全可以无缝衔接过来

比如大家常说的 C++ 类class,在我看来本质就是 C 语言结构体struct的 "超级加强版"------C 的结构体只能存数据,而 C++ 的类既能存数据,又能把操作数据的函数也包进去,这不就是我们写数据结构时一直想做的事吗?

先把 C 语言的数据结构练熟了,再回头学 C++ 的面向对象,反而更容易理解它为什么要这么设计。

二、先搞懂:C++ 到底是什么?

2.1 C++ 的诞生与发展

C++ 是由本贾尼・斯特劳斯特卢普(Bjarne Stroustrup)在 1979 年于贝尔实验室设计的,最初叫 "带类的 C",1983 年正式命名为 C++。

它的设计初衷就是在 C 语言的基础上,增加面向对象编程的特性,解决 C 语言在大型复杂软件开发中表达能力、可维护性不足的问题。

2.2 C++ 的主要版本

C++ 的标准一直在更新,每个版本都带来了新的特性,我们现在学习主要用 C++11 及以上的版本:

版本 发布时间 核心特性
C++98 1998 年 第一个官方标准,引入 STL 标准模板库
C++11 2011 年 革命性更新,lambda、右值引用、智能指针、线程库
C++14 2014 年 对 C++11 的完善和扩展
C++17 2017 年 结构化绑定、文件系统库
C++20 2020 年 协程、概念、模块化

这里插个有趣的瓜:C++23 本来计划加入网络库,结果因为标准委员会内部关于 senders/receivers 的争论,最终推迟到了 C++26,网上吐槽说 "等 C++ 网络库出来,我都退休了"。

2.3 C++ 和 C 的关系

  • 完全兼容:绝大多数 C 代码可以直接在 C++ 编译器下运行
  • 向下兼容:C 的所有语法在 C++ 中都能用
  • 扩展增强:在 C 的基础上增加了面向对象、泛型编程、异常处理等特性
  • 适用场景:C 更适合底层、性能要求极高的场景;C++ 更适合大型复杂项目的开发

三、我的第一批 C++ 练习

3.1 Cpp start:第一个 C++ 程序

cpp 复制代码
#include<iostream>
using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    return 0;
}

知识点详解:

  1. #include<iostream>:引入 C++ 标准输入输出流头文件,对应 C 语言的stdio.h
  2. using namespace std;:展开标准命名空间,这样就不用写std::cout
  3. cout:标准输出对象,对应 C 语言的printf
  4. <<:流插入运算符,自动识别变量类型,不用手动指定格式符
  5. endl:输出换行并刷新缓冲区,对应 C 语言的'\n'
  6. C++ 程序的后缀是.cpp,用 g++ 编译器编译,而不是 gcc

3.2 namespace_test:命名空间

cpp 复制代码
namespace Luminous//单命名空间
{
    void sayHello()
    {
        cout<<"Hello Luminous!"<<endl;
    }
}

namespace working//命名空间的嵌套
{
    namespace Luminous
    {
        void sayHello()
        {
            cout<<"Hello working Luminous!"<<endl;
        }
    }
    int a = 10;
}

int main()
{
    Luminous::sayHello();//调用单命名空间中的函数
    working::Luminous::sayHello();//调用嵌套命名空间中的函数
    cout << "a的值为:" << working::a << endl;
    return 0;
}

知识点详解:

  1. 为什么需要命名空间?

    • 解决 C 语言中全局变量、函数的命名冲突问题
    • 比如 C 语言标准库有个rand()函数,如果你自己也定义一个rand变量,就会编译报错
    • 命名空间相当于给变量、函数套了个 "盒子",不同盒子里的同名变量不会冲突
  2. 命名空间的三种使用方式:

    • 方式 1:命名空间名::成员名(推荐,最安全)
    • 方式 2:using 命名空间名::成员名(展开单个成员)
    • 方式 3:using namespace 命名空间名(展开整个命名空间,小练习方便,大项目不推荐)
  3. 命名空间的特性:

    • 可以嵌套定义
    • 多个文件中定义的同名命名空间会自动合并
    • C++ 标准库的所有内容都放在std命名空间中

3.3 C++ 输入输出

cpp 复制代码
#include<iostream>
using namespace std;

int main()
{
    int a;
    double b;
    char c;
    cin >> a >> b >> c; // 连续输入多个变量,自动识别类型
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
    return 0;
}

知识点详解:

  1. cin:标准输入对象,对应 C 语言的scanf
  2. >>:流提取运算符,同样自动识别变量类型
  3. 对比 C 语言的优势:
    • 不用记%d%lf%c等格式符,不容易写错
    • 可以连续输入输出多个变量,代码更简洁
    • 支持自定义类型的输入输出(后面学类的时候会用到)

3.4 缺省函数:

cpp 复制代码
int add1(int a, int b = 10)//半缺省参数,b的默认值为10
{
    return a + b;
}

int add2(int a = 50, int b = 20)//全缺省参数,a和b都有默认值
{
    return a + b;
}

int main()
{
    cout<<"sum1="<<add1(10) << endl; // 只传a,b用默认值10,输出20
    cout << "sum2=" << add1(10, 20) << endl; // 传两个参数,用传入的值,输出30
    cout << "sum3=" << add2() << endl; // 都不传,用默认值50+20=70
    cout << "sum4=" << add2(5,10) << endl; // 传两个参数,输出15
    return 0;
}

知识点详解:

  1. 什么是缺省参数?

    • 声明或定义函数时,给参数指定一个默认值
    • 调用函数时,如果没有传这个参数,就用默认值;如果传了,就用传入的值
  2. 缺省参数的规则:

    • 半缺省参数必须从右往左依次连续缺省,不能间隔跳跃
    • 函数调用时,实参必须从左往右依次传递,不能跳跃
    • 函数声明和定义分离时,缺省参数只能写在声明中,不能同时写在声明和定义里
  3. 作用:

    • 简化函数调用,不用为了不同的参数个数写多个重载函数
    • 提高代码的灵活性

3.5 函数重载 test:函数重载

cpp 复制代码
int Add(int a, int b)//函数重载1:int类型
{
    return a + b;
}

double Add(double a, double b)//函数重载2:double类型
{
    return a + b;
}

int main()
{
    int a = 10, b = 20;
    int sum1 = Add(a, b);
    cout << "sum1 = " << sum1 << endl; // 输出30
    
    double c = 15.5, d = 25.6;
    double sum2 = Add(c, d);
    cout << "sum2 = " << sum2 << endl; // 输出41.1
    return 0;
}

知识点详解:

  1. 什么是函数重载?

    • C++ 允许在同一作用域中定义多个同名函数
    • 要求这些函数的形参列表不同(参数个数不同、参数类型不同、参数类型顺序不同)
    • 编译器会根据实参的类型和个数,自动匹配对应的函数
  2. 注意:

    • 返回值不同不能作为函数重载的条件(因为调用时无法区分)
    • 缺省参数可能导致函数重载产生歧义(比如两个函数都能匹配同一个调用)
  3. C 语言为什么不支持函数重载?

    • C 语言编译后,函数名就是原来的名字,比如Add编译后还是_Add
    • C++ 编译后,函数名会包含参数类型信息,比如int Add(int,int)编译后变成_Add_int_int
    • 这样不同参数的同名函数,编译后的名字就不一样了,不会冲突

3.6 引用 test:引用

cpp 复制代码
// 传值:不能交换,因为传的是副本
void change1(int c, int d)
{
    int a = c;
    c = d;
    d = a;
}

// 引用传参:可以交换,传的是变量本身
void change2(int& c, int& d)
{
    int a = c;
    c = d;
    d = a;
}

// 指针传参:可以交换,传的是变量的地址
void change3(int* c, int* d)
{
    int a = *c;
    *c = *d;
    *d = a;
}

int main()
{
    int a = 10, b = 20;
    change1(a, b);
    cout << "change1后:a = " << a << ", b = " << b << endl; // 不变
    
    int c = 10, d = 20;
    change2(c, d);
    cout << "change2后:c = " << c << ", d = " << d << endl; // 交换成功
    
    int e = 10, f = 20;
    change3(&e,&f);
    cout << "change3后:e = " << e << ", f = " << f << endl; // 交换成功
    return 0;
}

知识点详解:

  1. 什么是引用?

    • 引用不是新定义一个变量,而是给已存在的变量取一个别名
    • 编译器不会为引用变量开辟内存空间,它和引用的变量共用同一块内存空间
    • 语法:类型& 引用名 = 引用对象;
  2. 引用的特性:

    • 引用在定义时必须初始化
    • 一个变量可以有多个引用
    • 引用一旦引用一个实体,就不能再引用其他实体(这是和指针最大的区别)
  3. 引用的使用场景:

    • 引用传参:代替指针传参,代码更简洁,不容易出错
    • 引用做返回值:减少拷贝,提高效率(后面学类的时候会详细讲)
  4. 引用和指针的区别:

    • 引用是别名,不开空间;指针是存储地址的变量,开空间
    • 引用必须初始化;指针可以不初始化(但不推荐)
    • 引用不能改变指向;指针可以改变指向
    • 引用没有空引用;指针有空指针

四、学习方法和资源推荐

4.1 我的学习方法

  1. 上课认真听:跟着学校老师的节奏走,先把基础概念搞懂
  2. 课后必写代码:每个知识点都自己写一遍测试用例,运行出错了再去查资料
  3. 写博客总结:每学完一个章节就写一篇博客,既能巩固知识,也能方便以后复习
  4. 结合数据结构:用 C++ 重写之前学过的 C 语言数据结构,既能练 C++,又能加深对数据结构的理解

4.2 资源推荐

网上流传的 "21 天精通 C++" 只是个梗,C++ 是一门需要长期学习的语言,不用追求速成,一步一个脚印就好。

最后

从 C 到 C++,不是从零开始,而是站在之前的基础上更上一层楼。如果你也刚学完 C 语言,正在学 C++,不用害怕它的语法复杂,很多东西我们其实已经在 C 语言里接触过了,只是换了一种更优雅的写法。

接下来的日子,一起加油吧!

相关推荐
超梦dasgg1 小时前
Java 生产环境分布式定时任务全解(实战落地版)
java·开发语言·分布式
Legendary_0081 小时前
18-30W 便携照明设备 USB-C PD 升级:选型与设计要点
c语言·开发语言
破土士V1 小时前
Java基础知识集合
java·开发语言
keykey6.1 小时前
从感知机到神经网络:深度学习的起源
开发语言·人工智能·深度学习·机器学习
ZC跨境爬虫1 小时前
跟着 MDN 学JavaScript day_5:技能测试——变量实战
java·开发语言·前端·javascript
星恒随风1 小时前
C++ 类和对象入门(一):从 class、访问限定符到 this 指针
开发语言·c++·笔记·学习·状态模式
赵民勇1 小时前
如何查看一个二进制程序是否设置了rpath或runpath?
linux·c++
Brilliantwxx1 小时前
【C++】 哈希表 unordered_map 与 unordered_set(底层原理 + 线性哈希表代码实现)
开发语言·c++·散列表
瑞雪兆丰年兮1 小时前
[0开始学Java|第二十四天]集合(Map&可变参数&集合工具类Collections)
java·开发语言·map·collections