C++基础:关于C与C++的学习记录

导读:很多初学者在从C语言过渡到C++时,往往只学到了"带类的C",而忽略了C++在底层机制、内存管理和IO流上的全面革新。本文带你系统梳理C与C++的核心差异,详解C++新增语法、流式IO以及堆内存管理(含智能指针),以下是我在职坐标的学习记录:

一、C与C++的区别

C++并非仅仅是C语言的超集,它在设计哲学和底层实现上都有着本质的不同。以下是两者的核心区别对比:

对比维度 C语言 C++
编程范式 面向过程(Procedure-Oriented) 多范式(面向对象、泛型、函数式等)
类型系统 弱类型,隐式转换多 强类型,类型检查更严格
标准库 标准C库(stdio.h, string.h等) STL(容器、算法、迭代器)及IO流
异常处理 依赖返回值和setjmp/longjmp try-catch-throw 异常处理机制
泛型编程 宏定义或void*指针 模板(Template)
命名空间 无,易产生命名冲突 namespace 解决命名污染
函数/运算符 不支持重载 支持函数重载与运算符重载
内联函数 仅支持宏定义 #define 支持 inline 关键字
内存管理 malloc/free new/delete 及智能指针

1. 编程范式差异

C语言注重步骤和算法,而C++引入了面向对象(OOP),将数据和操作数据的方法封装在一起。

// C语言风格:数据与操作分离
struct Point { int x; int y; };
void move(Point* p, int dx) { p->x += dx; }

// C++风格:封装
class Point {
    int x, y;
public:
    void move(int dx) { x += dx; }
};

2. 引用与指针的区别

C++引入了引用(Reference),它是已存在变量的别名,必须在定义时初始化,且不能重新绑定,没有空引用的概念。

int a = 10;
int &ref = a;  // 引用
int *ptr = &a; // 指针

ref = 20;      // 直接修改了a的值
*ptr = 30;     // 通过解引用修改a的值

二、C++在C基础语法上新增的内容

C++在C的基础上极大地丰富了语法糖和底层特性,以下是核心新增内容:

1. 类与结构体(class vs struct)

在C++中,structclass 的唯一区别是默认访问权限struct 默认是 public,而 class 默认是 private

struct MyStruct {
    int data; // 默认 public
};

class MyClass {
    int data; // 默认 private
};

2. 函数重载与默认参数

C++允许同名函数拥有不同的参数列表(编译器通过名称修饰 Name Mangling 实现)。同时支持默认参数,但默认参数必须从右向左依次定义。

void print(int a) { /*...*/ }
void print(int a, int b) { /*...*/ } // 重载

void log(const char* msg, int level = 0) { /*...*/ } // 默认参数

3. 构造函数、析构函数与 this 指针

C++的类可以拥有生命周期管理函数。this 指针是一个隐含的指针,指向调用成员函数的对象实例。

class Student {
    std::string name;
public:
    Student(const std::string& n) : name(n) {} // 构造函数
    ~Student() {}                              // 析构函数
    
    void show() const {
        std::cout << this->name << std::endl;  // this指针
    }
};

4. const 的增强

在C++中,const 不仅可以修饰变量,还可以修饰指针、引用,甚至修饰成员函数(保证不修改成员变量)。

const int* p1;       // 指向常量的指针
int* const p2;       // 常量指针
void func() const {} // const成员函数

5. 强类型枚举(enum class)

C++11 引入了 enum class,避免了传统枚举的隐式类型转换和命名空间污染。

enum class Color { Red, Green, Blue };
Color c = Color::Red;
// int x = c; // 编译错误!不能隐式转换为int

6. 模板

模板实现了编译时的泛型编程;异常处理将错误处理逻辑与正常业务逻辑分离。

// 模板
template<typename T>
T add(T a, T b) { return a + b; }

三、C++的输入和输出

C++ 使用 <iostream> 库进行流式IO,相比C语言的 printf/scanf,它类型安全易于扩展

1. cin 和 cout 的基本用法

使用 << 插入运算符和 >> 提取运算符。

#include <iostream>
int main() {
    std::string name;
    int age;
    std::cout << "Enter name and age: ";
    std::cin >> name >> age;
    std::cout << "Hello " << name << ", you are " << age << std::endl;
    return 0;
}

2. 格式化输出

借助 <iomanip> 头文件,可以非常方便地控制输出格式。

#include <iostream>
#include <iomanip>
int main() {
    double pi = 3.1415926;
    // 固定小数位,保留3位
    std::cout << std::fixed << std::setprecision(3) << pi << std::endl; 
    // 宽度为10,不足部分用'*'填充
    std::cout << std::setw(10) << std::setfill('*') << 42 << std::endl; 
    return 0;
}

3. 输入输出状态标志

流对象有内部状态,可以通过 good(), fail(), eof(), bad() 进行检查。

int num;
std::cin >> num;
if (std::cin.fail()) {
    std::cout << "Input is not a number!" << std::endl;
    std::cin.clear(); // 清除错误标志
    std::cin.ignore(10000, '\n'); // 忽略缓冲区残留字符
}

4. 文件输入输出

使用 <fstream> 进行文件读写。

#include <fstream>
int main() {
    // 写入文件
    std::ofstream outFile("test.txt");
    outFile << "Hello, File IO!" << std::endl;
    outFile.close();

    // 读取文件
    std::ifstream inFile("test.txt");
    std::string line;
    while (std::getline(inFile, line)) {
        std::cout << line << std::endl;
    }
    return 0;
}

5. 标准I/O对象的关联与取消关联

默认情况下,C++的 cin/cout 与C的 stdin/stdout 是绑定的。在需要极高IO性能的场景(如算法竞赛),可以取消关联:

std::ios::sync_with_stdio(false);
std::cin.tie(nullptr); // 解除cin与cout的绑定

四、C++的堆内存申请和释放

C++将堆内存管理的控制权交给了程序员,但也提供了更安全的机制。

1. new 和 delete 的基本用法

new 不仅分配内存,还会调用构造函数delete 释放内存前会调用析构函数

int* p = new int(42); // 分配并初始化
delete p;             // 释放内存
p = nullptr;          // 防止悬空指针

2. new[] 和 delete[]

对于数组,必须使用 new[]delete[] 匹配,否则会导致未定义行为(尤其是类对象数组)。

int* arr = new int[10];
delete[] arr;

3. new 的初始化方式

int* a = new int;        // 默认初始化(值不确定)
int* b = new int();      // 值初始化(初始化为0)
int* c = new int(10);    // 直接初始化
int* d = new int{20};    // 列表初始化(C++11)

4. 智能指针

RAII(资源获取即初始化)是C++的核心思想:将资源的生命周期绑定到对象的生命周期。现代C++强烈建议使用智能指针代替裸指针。

#include <memory>
int main() {
    // unique_ptr: 独占所有权
    auto up = std::make_unique<int>(42);
    
    // shared_ptr: 共享所有权,引用计数
    auto sp1 = std::make_shared<int>(100);
    auto sp2 = sp1; // 引用计数变为2
    
    // weak_ptr: 不增加引用计数,解决循环引用
    std::weak_ptr<int> wp = sp1; 
    return 0; // 离开作用域,内存自动释放
}

5. new/delete 与 malloc/free 的对比

特性 malloc / free new / delete
类型 C库函数 C++运算符
构造/析构 不调用 自动调用
返回值 void*,需强转 具体类型指针
失败处理 返回 NULL 抛出异常 / nothrow
内存大小 需手动计算字节数 自动计算

最佳实践:在现代C++中,永远不要手动 new/delete。优先使用容器(如 std::vector)和智能指针(std::unique_ptr, std::shared_ptr)。

总结与展望

从C到C++,我们跨越的不仅仅是语法的增加,更是编程思维的升华。C++在保留C语言高效底层控制力的同时,通过面向对象、泛型编程和RAII等机制,极大地提升了代码的抽象能力和安全性。

posted @ 2026-08-21 19:10  Solitude0420  阅读(3)  评论(0)    收藏  举报