专业编程基础技术教程

网站首页 > 基础教程 正文

JS程序员学C++入门教程(中篇)

ccvgpt 2025-04-26 17:05:00 基础教程 2 ℃

1. 内存管理基础

JavaScript (自动垃圾回收)

// JS 自动管理堆内存
let obj = { data: 100 }; 
obj = null; // 对象将被 GC 回收

C (手动内存管理)

#include <stdlib.h>
void demo() {
    int* arr = (int*)malloc(3 * sizeof(int)); // 堆分配
    arr[0] = 10;
    free(arr); // 必须手动释放
    // 若忘记 free 会导致内存泄漏
}

C++ (手动 + RAII 原则)

void demo() {
    int* arr = new int[3]; // 堆分配
    arr[0] = 10;
    delete[] arr; // 手动释放

    // 更安全的做法:使用智能指针(下篇详述)
    std::unique_ptr<int[]> safeArr(new int[3]);
}

JS 程序员注意

  1. C/C++ 中堆内存必须手动释放(JS 无此概念)
  2. 忘记 delete 或 free 会导致内存泄漏
  3. 使用 new/delete 而非 C 的 malloc/free(避免混用)

2. 面向对象编程

JavaScript (原型链)

class JsAnimal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} makes a noise`);
    }
}

class JsDog extends JsAnimal {
    speak() {
        super.speak();
        console.log("Woof!");
    }
}

const dog = new JsDog("Buddy");
dog.speak();

C (结构体 + 函数指针)

// 模拟面向对象
typedef struct {
    char name[20];
    void (*speak)(void* self); // 函数指针
} Animal;

void animalSpeak(void* self) {
    Animal* a = (Animal*)self;
    printf("%s makes a noise\n", a->name);
}

typedef struct {
    Animal base;
} Dog;

void dogSpeak(void* self) {
    Animal* a = (Animal*)self;
    animalSpeak(self); // 类似 super 调用
    printf("Woof!\n");
}

int main() {
    Dog dog = { .base = { .name = "Buddy", .speak = dogSpeak } };
    dog.base.speak(&dog); // 手动传递 this 指针
}

C++ (类与继承)

#include <iostream>
class Animal {
public:
    Animal(const std::string& name) : name(name) {}
    virtual void speak() { // 虚函数实现多态
        std::cout << name << " makes a noise" << std::endl;
    }
protected:
    std::string name;
};

class Dog : public Animal {
public:
    Dog(const std::string& name) : Animal(name) {}
    void speak() override { // C++11 明确 override
        Animal::speak();     // 调用父类方法
        std::cout << "Woof!" << std::endl;
    }
};

int main() {
    Dog dog("Buddy");
    dog.speak();
    // 输出:
    // Buddy makes a noise
    // Woof!
}

核心差异

JS程序员学C++入门教程(中篇)

  • C++ 类有明确的访问控制(public/protected/private)
  • 虚函数表(vtable)实现动态多态(JS 原型链查找类似动态绑定)
  • 析构函数可手动定义资源释放逻辑(JS 无此机制)

3. 构造函数与析构函数

JavaScript (无显式析构)

class JsFile {
    constructor(filename) {
        this.handle = openFile(filename); 
    }
    // 无标准析构方法,依赖 GC 回收
}

// 使用 WeakRef/FinalizationRegistry 模拟析构
const registry = new FinalizationRegistry(handle => {
    closeFile(handle);
});
let obj = new JsFile("test.txt");
registry.register(obj, obj.handle);

C++ (显式生命周期控制)

class File {
public:
    File(const std::string& filename) {
        handle = fopen(filename.c_str(), "r");
        if (!handle) throw std::runtime_error("File open failed");
    }
    ~File() { // 析构函数确保资源释放
        if (handle) fclose(handle);
    }
private:
    FILE* handle;
};

// 使用示例
void readFile() {
    File file("test.txt"); // 构造函数调用
    // 文件操作...
} // 离开作用域时析构函数自动调用

关键陷阱

  1. C++ 中未正确释放资源(如文件句柄)会导致资源泄漏
  2. JS 依赖 GC 回收,时机不可控

4. 多态与虚函数

JavaScript (动态类型)

class Shape {
    area() { throw "Not implemented"; }
}

class Circle extends Shape {
    constructor(r) { super(); this.radius = r; }
    area() { return Math.PI * this.radius ** 2; }
}

// 运行时多态
function printArea(shape) {
    console.log(shape.area());
}

printArea(new Circle(5)); // 78.54...

C++ (虚函数表)

class Shape {
public:
    virtual double area() const { 
        throw std::logic_error("Not implemented");
    }
    virtual ~Shape() = default; // 虚析构函数确保正确释放
};

class Circle : public Shape {
public:
    Circle(double r) : radius(r) {}
    double area() const override { 
        return 3.14159 * radius * radius; 
    }
private:
    double radius;
};

void printArea(const Shape& shape) {
    std::cout << shape.area() << std::endl;
}

int main() {
    Circle c(5);
    printArea(c); // 输出 78.5397
}

JS 程序员注意

  1. C++ 必须通过虚函数 (virtual) 实现多态
  2. 基类析构函数应为虚函数(否则通过基类指针删除子类对象时行为未定义)

5. 运算符重载

JavaScript (无法重载运算符)

class Vector {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    add(other) { // 手动实现加法
        return new Vector(this.x + other.x, this.y + other.y);
    }
}

const v1 = new Vector(1, 2);
const v2 = new Vector(3, 4);
const v3 = v1.add(v2);

C++ (运算符重载)

class Vector {
public:
    Vector(double x, double y) : x(x), y(y) {}
    Vector operator+(const Vector& other) const { // 重载 +
        return Vector(x + other.x, y + other.y);
    }
private:
    double x, y;
};

int main() {
    Vector v1(1, 2), v2(3, 4);
    Vector v3 = v1 + v2; // 直接使用运算符
}

关键差异

  • C++ 允许重载 +, <<, == 等运算符(JS 不支持)
  • 运算符重载需遵循特定语法规则(如参数数量)

6. 异常处理对比

JavaScript (动态异常)

function riskyOperation() {
    throw new Error("Something went wrong");
}

try {
    riskyOperation();
} catch (e) {
    console.error(e.message);
}

C++ (类型安全异常)

#include <stdexcept>
void riskyOperation() {
    throw std::runtime_error("Something went wrong");
}

int main() {
    try {
        riskyOperation();
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}

关键陷阱

  1. C++ 异常需继承自 std::exception(JS 可抛出任意值)
  2. 栈展开时会调用局部对象的析构函数(RAII 保障资源安全)

本章小结

  • 内存管理:理解堆/栈差异,掌握 new/delete 和 RAII 模式
  • 面向对象:类、继承、多态的实现方式与 JS 原型链的对比
  • 高级特性:运算符重载、友元函数、常量正确性
  • 核心思维转变:从自动内存管理转向精确控制对象生命周期

Tags:

最近发表
标签列表