《C++ 基石:筑牢编程巅峰根基》

发布于:2025-03-28 ⋅ 阅读:(29) ⋅ 点赞:(0)

一、C++ 头文件

1. 面向对象基础

  • 对象:在 C++ 中,对象是类的实例化。它结合了 C 语言的数据(属性)和 C 语言操作函数(方法)。例如,定义一个简单的 Person 类:
class Person {
private:
    std::string name;
    int age;
public:
    Person(std::string n, int a) : name(n), age(a) {}
    void introduce() {
        std::cout << "Name: " << name << ", Age: " << age << std::endl;
    }
};

        这里 Person 类封装了数据成员 name 和 age,以及成员函数 introduce。通过创建 Person 类的对象,就可以调用其成员函数进行操作。

2. 兼容 C 语言头文件

        C++ 兼容 C 语言头文件,有些有自己的风格(无后缀),部分 C 语言头文件加 c 前缀(如 cstdio 对应 C 语言的 stdio.h)。例如使用 C 语言风格的输入输出函数:

#include <cstdio>
int main() {
    int num = 10;
    printf("The number is %d\n", num);
    return 0;
}

        原理是 C++ 为了保持对 C 语言的兼容性,对 C 语言库进行了重新包装,以符合 C++ 的命名空间等规则。

二、命名空间

1. 作用

        防止多人项目代码中同名冲突。例如,不同团队开发的代码中可能都有一个叫 print 的函数,通过命名空间可以区分:

namespace TeamA {
    void print() {
        std::cout << "This is from TeamA" << std::endl;
    }
}
namespace TeamB {
    void print() {
        std::cout << "This is from TeamB" << std::endl;
    }
}

2. 创建与使用

  • 创建:使用 namespace 关键字 + 命名空间名,如 namespace MyNamespace { /* 代码 */ }
  • 使用
    • 大范围全部使用:using namespace 命名空间名
    • 大范围指定使用:using 命名空间名::标识符
    • 小范围指定:命名空间名::项
int main() {
    TeamA::print(); // 明确指定调用TeamA命名空间的print函数
    using TeamB::print; // 引入TeamB命名空间的print函数
    print();
    return 0;
}

3. 作用域运算符

        作用域运算符 :: 用于解决命名冲突,当不同命名空间或全局作用域与局部作用域有同名变量或函数时,通过 :: 可以明确指定使用哪个作用域的实体。例如:

int globalNum = 10;
int main() {
    int globalNum = 20;
    std::cout << ::globalNum << std::endl; // 输出全局作用域的globalNum,即10
    std::cout << globalNum << std::endl; // 输出局部作用域的globalNum,即20
    return 0;
}

4. 重名问题

        编译器会将同名的命名空间合并,但内部重名的变量或函数会报错。例如:

namespace Shared {
    int value = 5;
}
namespace Shared {
    // 这里如果再定义int value会报错
    void func() {
        std::cout << "In Shared namespace" << std::endl;
    }
}

5. 函数定义

        如果函数声明在命名空间内,定义可以在外部,但需要指定命名空间。例如:

namespace Utility {
    void printMessage();
}
void Utility::printMessage() {
    std::cout << "This is a message from Utility namespace" << std::endl;
}
int main() {
    Utility::printMessage();
    return 0;
}

三、标准输入输出

1. 标准输入

        使用 std::cin >> 变量 进行输入。例如:

int num;
std::cout << "Enter a number: ";
std::cin >> num;
std::cout << "You entered: " << num << std::endl;

        原理是 cin 是 istream 类的对象,>> 运算符被重载用于从标准输入流(键盘)读取数据并存储到指定变量中。

2. 标准输出

        使用 std::cout << 内容 << std::endl 进行输出,std::endl 会输出换行并刷新缓冲区。例如:

std::cout << "Hello, World!" << std::endl;

  cout 是 ostream 类的对象,<< 运算符被重载用于将数据输出到标准输出流(屏幕)。

四、引用

1. 类型

        数据类型 & 变量名(如 int& ref),还存在被引用变量的情况。

2. 作用

        给变量取别名,与变量共享内存。例如:

int num = 10;
int& ref = num;
ref = 20; // 此时num也变为20
std::cout << "num: " << num << ", ref: " << ref << std::endl;

3. 特点

  • 常量不能被普通引用绑定,但常量引用可绑定常量和变量。
  • 必须初始化,如 int& ref; 是错误的,应 int num; int& ref = num;
  • 无法更换更改为对象,一旦引用绑定到某个变量,就不能再指向其他变量。
  • 引用和变量类型需相同。

4. 练习示例

        可编写函数利用引用交换两个整数的值:

void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}
int main() {
    int x = 5, y = 10;
    swap(x, y);
    std::cout << "x: " << x << ", y: " << y << std::endl;
    return 0;
}

五、其他数据类型

1. bool 类型

        占 1 字节,true 对应非零值(一般为 1),false 对应 0 值。例如:

bool flag = true;
if (flag) {
    std::cout << "The flag is true" << std::endl;
}

2. string 类型

        可进行直接操作,如复制、拼接、比较等,可和 const char* 相互转换。例如:

#include <string>
int main() {
    std::string str1 = "Hello";
    std::string str2 = "World";
    std::string result = str1 + " " + str2; // 拼接
    std::cout << result << std::endl;
    const char* cstr = result.c_str(); // 转换为const char*
    std::string str3(cstr); // 从const char*转换回string
    return 0;
}

3. auto 类型(C++11 起可用)

        能自动推导类型,例如:

auto num = 10; // 自动推导num为int类型
auto str = std::string("Auto type"); // 自动推导str为std::string类型

        原理是编译器根据初始化表达式的类型来确定 auto 声明的变量类型。

六、名词解释

1. 类

        C++ 中类是对 C 语言结构体的扩展,struct 在 C++ 中也可当作类使用。例如:

class Rectangle {
private:
    int width;
    int height;
public:
    Rectangle(int w, int h) : width(w), height(h) {}
    int area() {
        return width * height;
    }
};

2. 对象

        类产生的变量,类中可包含结构体变量。例如:

Rectangle rect(5, 3); // 创建Rectangle类的对象rect
std::cout << "Area: " << rect.area() << std::endl;

3. struct 区别

        C++ 中的 struct 可存放函数和变量,与 class 主要区别在于默认访问权限,struct 默认成员为 publicclass 默认成员为 private。例如:

struct Point {
    int x;
    int y;
    void print() {
        std::cout << "(" << x << ", " << y << ")" << std::endl;
    }
};
class Circle {
    int radius;
public:
    Circle(int r) : radius(r) {}
    int getRadius() {
        return radius;
    }
};

4. 类种类

        常见的有 structunionclass,一般常用 struct(多用于简单数据结构)和 class(用于更复杂的面向对象设计)。

5. 访问权限

  • public:成员公开,类内外都可访问。
  • private:成员私有,只有类内成员函数可访问。
  • protected:受保护,类内和派生类内可访问。例如:
class Base {
private:
    int privateData;
protected:
    int protectedData;
public:
    int publicData;
};
class Derived : public Base {
public:
    void accessData() {
        // 不能访问privateData
        // 可以访问protectedData
        protectedData = 10; 
        publicData = 20;
    }
};

6. 数据分类规则

        成员属性一般设为私有,通过公开的成员方法(如 getter 和 setter 函数)来访问和修改,以实现数据封装和保护。例如:

class Student {
private:
    std::string name;
    int age;
public:
    Student(std::string n, int a) : name(n), age(a) {}
    std::string getName() const {
        return name;
    }
    int getAge() const {
        return age;
    }
};

7. 内外访问取向

        访问成员位置是否在类作用域内判断访问权限是否允许。在类外只能访问 public 成员,在类内可访问所有权限成员。

七、struct 和 class 区别

        除了默认访问权限不同(struct 默认 publicclass 默认 private),在继承等特性上,语法使用基本一致。例如:

struct BaseStruct {
    int baseData;
};
class DerivedClass : public BaseStruct {
public:
    void useBaseData() {
        baseData = 10;
    }
};

        这里 DerivedClass 以 public 方式继承 BaseStruct,可以访问 BaseStruct 的 public 成员 baseData

八、类的初始化

1. 分支主题 - 构造函数及相关知识

  • 特点:创建对象时自动调用,与类名相同,无返回值类型,可重载,形参列表表明类型不同。例如:
class Complex {
private:
    double real;
    double imag;
public:
    Complex() : real(0), imag(0) {} // 默认构造函数
    Complex(double r, double i) : real(r), imag(i) {} // 带参数构造函数
    void print() {
        std::cout << real << " + " << imag << "i" << std::endl;
    }
};
  • 调用方式
    • 多种显式调用方式,如 Complex c1(1, 2);(直接初始化),Complex c2 = Complex(3, 4);(复制初始化)。
    • 隐式调用(部分拆分),如 Complex c3 = {5, 6};
    • 可用 explicit 关键字禁止隐式转换构造,如 explicit Complex(double r) : real(r), imag(0) {},此时 Complex c = 7; 这种隐式转换构造就会报错。
  • 接口:类内提供外部修改及访问成员数据的函数,常为 getter(获取数据,如 const 成员函数保证不修改数据)和 setter 函数(设置数据)。例如:
class Person {
private:
    std::string name;
public:
    Person(std::string n) : name(n) {}
    std::string getName() const {
        return name;
    }
    void setName(std::string n) {
        name = n;
    }
};

九、C++ 中的 const

1. 函数传参尽量用 const 修饰

        可以防止函数内部意外修改传入的参数。例如:

void printString(const std::string& str) {
    // 这里不能修改str
    std::cout << str << std::endl;
}

2. 普通指针和 const 指针转换规则严格

  • 指向常量的指针const int* ptr;,不能通过该指针修改所指的值,但指针本身可以指向其他地址。例如:
const int num = 10;
const int* ptr = &num;
// *ptr = 20; 错误,不能通过ptr修改num的值
int anotherNum = 20;
ptr = &anotherNum; // 正确,指针可以指向其他地址
  • 常量指针int* const ptr;,指针本身不能再指向其他地址,但可以通过指针修改所指的值(如果值本身不是常量)。例如:
int num = 10;
int* const ptr = &num;
*ptr = 20; // 正确,可以修改所指的值
// ptr = &anotherNum; 错误,指针不能再指向其他地址

十、this 指针

        对象调用成员方法时,其地址作为隐藏参数传入,类成员函数内指向当前对象地址。this 指针是常量指针,指向不可变,但可通过在函数声明与定义间加 const 限定其指向的对象为常量。例如:

class Counter {
private:
    int count;
public:
    Counter() : count(0) {}
    void increment() {
        this->count++; // 通过this指针访问成员变量
    }
    int getCount() const {
        return count;
    }
};

        在 increment 函数中,this 指针指向调用该函数的 Counter 对象,从而可以访问和修改对象的成员变量 count。在 getCount 函数中,由于函数声明为 constthis 指针指向的对象被视为常量,不能通过 this 指针修改对象成员。

十一、列表初始化

        用于初始化类成员属性,构造函数编译器先执行列表初始化部分,再执行用户自定义执行部分。例如:

class Point {
private:
    int x;
    int y;
public:
    Point(int a, int b) : x(a), y(b) {
        // 这里是用户自定义执行部分,列表初始化先完成x和y的初始化
    }
    void print() {
        std::cout << "(" << x << ", " << y << ")" << std::endl;
    }
};

        在创建 Point 对象时,先通过列表初始化对 x 和 y 进行赋值,然后再执行构造函数体内的其他代码(如果有)。

十二、思维导图