前端从零学C++(三):C++基础

136 阅读11分钟

一、背景

我是一个 C/C++ 都没实战经验的前端开发,C 在几年前有了解过一些语法知识,下面我按照《C++ Primer第五版》,跟着一起学习 C++ 基础知识。

注:本文要求至少有一门编程语言的基础。

我的电脑环境:

  • mac
  • vscode 1.88.1

往期精彩:

下面是对你提供的大纲的详细完善和细化。每个部分都涵盖了相关的 C++ 基础知识,并解释了概念和用法。

二、语句

1. 简单语句

定义:简单语句是 C++ 中最基本的语句,它通常包含一个操作或指令,用来完成具体的任务。

类型

  • 表达式语句:执行某个操作或计算并通常返回结果。示例:
    int a = 5;  // 声明并初始化变量 a
    a = a + 1;  // 将 a 增加 1
    
  • 赋值语句:将值赋给变量。示例:
    int x = 10; // 赋值语句将 10 赋值给变量 x
    
  • 函数调用语句:调用函数并执行其功能。示例:
    std::cout << "Hello, World!"; // 调用 std::cout 函数输出字符串
    

2. 语句作用域

定义:作用域指的是变量和其他标识符在程序中可见的范围。语句作用域控制变量的生命周期和访问权限。

类型

  • 块作用域:在花括号 {} 内部定义的变量,其作用域仅限于这个块。示例:
    {
        int x = 10;  // x 的作用域仅限于此块
    }
    // x 在这里不可见
    
  • 函数作用域:函数内部的变量在函数外部不可见。示例:
    void myFunction() {
        int y = 20;  // y 的作用域仅限于 myFunction
    }
    // y 在这里不可见
    
  • 全局作用域:在所有函数之外定义的变量,对整个程序可见。示例:
    int globalVar = 30; // globalVar 的作用域是整个程序
    

3. 条件语句

定义:条件语句用于根据条件的真假来决定执行不同的代码块。

类型

  • if 语句:根据条件判断执行不同的代码块。示例:
    int a = 10;
    if (a > 5) {
        std::cout << "a is greater than 5";  // 当 a 大于 5 时执行
    }
    
  • if-else 语句:在 if 语句的基础上,增加 else 分支处理条件为假时的情况。示例:
    int a = 3;
    if (a > 5) {
        std::cout << "a is greater than 5";
    } else {
        std::cout << "a is not greater than 5"; // 当 a 不大于 5 时执行
    }
    
  • switch 语句:基于表达式的值选择执行不同的代码块。示例:
    int day = 3;
    switch (day) {
        case 1:
            std::cout << "Monday";
            break;
        case 2:
            std::cout << "Tuesday";
            break;
        case 3:
            std::cout << "Wednesday";  // 当 day 等于 3 时执行
            break;
        default:
            std::cout << "Invalid day";
            break;
    }
    

4. 迭代语句

定义:迭代语句用于重复执行一段代码,直到满足某个条件。

类型

  • for 循环:适用于已知次数的循环。示例:
    for (int i = 0; i < 5; ++i) {
        std::cout << i; // 输出 0 到 4
    }
    
  • while 循环:适用于条件为真的情况下重复执行。示例:
    int i = 0;
    while (i < 5) {
        std::cout << i;
        ++i;  // 输出 0 到 4
    }
    
  • do-while 循环:类似于 while 循环,但至少执行一次。示例:
    int i = 0;
    do {
        std::cout << i;
        ++i;  // 输出 0 到 4
    } while (i < 5);
    

5. 跳转语句

定义:跳转语句用于在代码中跳转到其他位置,通常用于控制流程。

类型

  • break:用于退出当前循环或 switch 语句。示例:
    for (int i = 0; i < 10; ++i) {
        if (i == 5) {
            break;  // 跳出循环
        }
        std::cout << i;
    }
    
  • continue:跳过当前迭代的剩余部分,继续下一次循环。示例:
    for (int i = 0; i < 10; ++i) {
        if (i % 2 == 0) {
            continue;  // 跳过偶数
        }
        std::cout << i;  // 只输出奇数
    }
    
  • goto:跳转到程序中的标签位置。虽然不推荐使用,但有时在特殊情况下可能有用。示例:
    int i = 0;
    start:
        std::cout << i;
        ++i;
        if (i < 5) goto start;  // 跳回 start 标签
    

6. try 语句块和异常处理

定义:异常处理用于捕获和处理程序运行时可能出现的错误,以便程序不会异常终止。

类型

  • try:用于定义可能会抛出异常的代码块。示例:
    try {
        // 代码块中可能抛出异常的部分
        int result = 10 / 0; // 可能抛出除零异常
    }
    
  • catch:用于捕获异常并处理。示例:
    try {
        int result = 10 / 0;
    } catch (const std::exception& e) {
        std::cout << "Exception caught: " << e.what();
    }
    
  • throw:用于抛出异常。示例:
    void function() {
        throw std::runtime_error("An error occurred");
    }
    
  • finally:在 C++ 中没有 finally 关键字,但可以使用 trycatch 块配合来实现类似的功能。

示例综合

#include <iostream>
#include <stdexcept>

void function() {
    throw std::runtime_error("An error occurred");
}

int main() {
    try {
        function();
    } catch (const std::exception& e) {
        std::cout << "Exception caught: " << e.what() << std::endl;
    }
    return 0;
}

总结

  • 简单语句:基本的操作指令,如赋值和函数调用。
  • 语句作用域:决定变量在程序中的可见范围。
  • 条件语句:用于在不同条件下执行不同的代码块。
  • 迭代语句:用于重复执行代码块。
  • 跳转语句:用于控制程序流程的跳转。
  • 异常处理:用于捕获和处理运行时错误,防止程序崩溃。

这些基础知识将帮助你在 C++ 编程中编写更清晰、更有效的代码。

C++ 的高级特性之一就是函数,它们是可重用的代码块,可以执行特定的任务。以下是关于函数的一些基础知识,包括它们的定义、使用方式以及一些高级特性。

三、函数

1. 函数基础

定义:函数是在程序中定义的代码块,它可以包括零个或多个操作,这些操作可以执行特定的任务。函数通常用于避免冗余代码和提高代码的可维护性。

语法

return_type function_name(parameter_list) {
    // 函数体
    return return_value; // 如果需要,返回一个值
}

例子

#include <iostream>

// 函数原型声明
void sayHello();

int main() {
    sayHello();
    return 0;
}

// 函数定义
void sayHello() {
    std::cout << "Hello, world!" << std::endl;
}

2. 参数传递

定义:函数调用时传递给函数的值称为参数。参数可以是任何类型的数据,包括基本类型、指针、引用和对象。

类型

  • 值传递:参数是复制原始数据的一份副本。示例:
    void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
  • 引用传递:参数是原始数据的别名。示例:
    void swapByReference(int &a, int &b) {
        int temp = a;
        a = b;
        b = temp;
    }
    
  • 指针传递:参数是一个指向原始数据的地址。示例:
    void swapByPointer(int *a, int *b) {
        int temp = *a;
        *a = *b;
        *b = temp;
    }
    

3. 返回类型和 return 语句

返回类型:声明函数将返回的值的类型。如果函数不需要返回值,则默认为 void

return 语句:用于从函数返回一个值。示例:

int square(int x) {
    return x * x;
}

例子

#include <iostream>

int sum(int a, int b) {
    return a + b;
}

int main() {
    int result = sum(3, 4); // result 现在被赋值为 7
    std::cout << result << std::endl;
    return 0;
}

4. 函数重载

定义:当具有相同名称的多个函数区分彼此的方式是参数的数量或类型时,这个过程称为函数重载。

类型

  • 参数数量:通过传递不同数量的参数。示例:
    void print() {
        std::cout << "No argument" << std::endl;
    }
    
    void print(int num) {
        std::cout << "One argument: " << num << std::endl;
    }
    
  • 参数类型:通过传递不同类型的参数。示例:
    void print(float num) {
        std::cout << "One argument: " << num << std::endl;
    }
    

5. 特殊用途语言特性

C++ 提供了几种特殊的函数,例如构造函数、复制构造函数、析构函数等。

构造函数:在对象创建时自动调用的函数。示例:

class MyClass {
public:
    MyClass() {
        std::cout << "Constructor called" << std::endl;
    }
};

复制构造函数:用于初始化一个已经创建的对象。示例:

class MyClass {
public:
    MyClass(const MyClass& other) {
        std::cout << "Copy constructor called" << std::endl;
    }
};

析构函数:当对象被销毁时自动调用的函数。示例:

class MyClass {
public:
    ~MyClass() {
        std::cout << "Destructor called" << std::endl;
    }
};

6. 函数匹配

C++ 编译器会根据调用参数的类型和数量来选择最佳匹配的函数。如果存在多种匹配方式,编译器会选择最精确的匹配类型。

7. 函数指针

定义:函数指针是一个存储函数位置(地址)的指针变量。

使用:函数指针可以被传递给其他函数、存储在数据结构中和用于回调。

例子

#include <iostream>

void func() {
    std::cout << "Hello, function pointer!" << std::endl;
}

int main() {
    void(*ptr)();  // 定义函数指针
    ptr = func;    // 指向函数 func
    ptr();         // 调用函数指针
    return 0;
}

结论:函数是C++编程中非常重要的一部分,它们可以组织代码、封装逻辑并重复使用。理解函数的基础知识将有助于写出高效且可维护的代码。

四、类

下面是关于 C++ 中类的详细说明,包括定义、访问控制、构造函数等内容。每一部分都进行了详细的解释和示例代码,旨在帮助你更好地理解类的各个方面。

1. 定义抽象数据类型

定义:类是 C++ 的核心特性之一,用于创建抽象数据类型(ADT)。它通过将数据和操作这些数据的函数封装在一起,提供了一个自定义的、模块化的数据结构。

语法

class ClassName {
public:
    // 构造函数
    ClassName();
    
    // 成员函数
    void memberFunction();

private:
    // 成员变量
    int memberVariable;
};

示例

#include <iostream>

class Rectangle {
public:
    // 构造函数
    Rectangle(int w, int h) : width(w), height(h) {}

    // 成员函数
    int area() {
        return width * height;
    }

private:
    int width;
    int height;
};

int main() {
    Rectangle rect(5, 10);
    std::cout << "Area: " << rect.area() << std::endl;
    return 0;
}

2. 访问控制与封装

访问控制:C++ 提供了三个访问控制级别:

  • public:公有成员,可以被任何函数访问。
  • protected:受保护成员,只能被类本身和派生类访问。
  • private:私有成员,只能被类本身访问。

封装:封装是将数据和操作数据的函数绑定在一起,并隐藏内部实现细节的一种机制。这样可以保护数据的完整性。

示例

#include <iostream>

class Person {
public:
    // 公有成员函数
    void setName(std::string n) {
        name = n;
    }

    void introduce() {
        std::cout << "Hi, I'm " << name << std::endl;
    }

private:
    // 私有成员变量
    std::string name;
};

int main() {
    Person p;
    p.setName("Alice");
    p.introduce();
    return 0;
}

3. 类的其他特性

成员函数:可以是普通成员函数、常量成员函数(不修改类的任何成员)或静态成员函数(与特定对象无关)。

构造函数:用于初始化对象。可以有多个构造函数(重载)。

析构函数:用于清理对象的资源,在对象生命周期结束时自动调用。

拷贝构造函数:用于创建对象的副本。

示例

#include <iostream>

class MyClass {
public:
    MyClass() { std::cout << "Constructor" << std::endl; }
    ~MyClass() { std::cout << "Destructor" << std::endl; }
    MyClass(const MyClass&) { std::cout << "Copy Constructor" << std::endl; }
};

int main() {
    MyClass obj1;       // 调用构造函数
    MyClass obj2 = obj1; // 调用拷贝构造函数
    return 0;
}

4. 类的作用域

定义:类的作用域指的是类的定义范围及其成员的可见性。在类内部定义的成员(变量和函数)只在该类的作用域内可见。

示例

#include <iostream>

class Outer {
public:
    class Inner {
    public:
        void display() {
            std::cout << "Inner class" << std::endl;
        }
    };
};

int main() {
    Outer::Inner obj;
    obj.display();
    return 0;
}

5. 构造函数再探

定义:构造函数是一种特殊的成员函数,用于初始化对象。在对象创建时自动调用。

构造函数的类型

  • 默认构造函数:无参数构造函数。
  • 参数化构造函数:有参数的构造函数,用于初始化对象时提供初值。
  • 复制构造函数:用于用现有对象初始化新对象。

示例

#include <iostream>

class Box {
public:
    Box() : length(0), width(0), height(0) {} // 默认构造函数
    Box(int l, int w, int h) : length(l), width(w), height(h) {} // 参数化构造函数
    Box(const Box &b) : length(b.length), width(b.width), height(b.height) {} // 复制构造函数

    void display() {
        std::cout << "Length: " << length << ", Width: " << width << ", Height: " << height << std::endl;
    }

private:
    int length, width, height;
};

int main() {
    Box b1;
    Box b2(3, 4, 5);
    Box b3(b2);

    b1.display();
    b2.display();
    b3.display();
    return 0;
}

6. 类的静态成员

定义:静态成员属于类而不是类的某个实例。这意味着所有实例共享同一个静态成员。

静态成员变量:在类外部进行初始化。

静态成员函数:不能访问类的非静态成员,只能访问静态成员。

示例

#include <iostream>

class Counter {
public:
    Counter() { ++count; }
    static int getCount() {
        return count;
    }

private:
    static int count; // 静态成员变量
};

int Counter::count = 0; // 静态成员变量的初始化

int main() {
    Counter c1, c2;
    std::cout << "Number of instances: " << Counter::getCount() << std::endl;
    return 0;
}

总结:理解类的基本概念、访问控制、构造函数及静态成员对于编写高效的 C++ 程序至关重要。通过以上示例和解释,你可以更好地掌握 C++ 类的各个方面。