C++ 是一种高性能的编程语言,允许程序员对内存管理进行精细控制。了解 C++ 的基本语法和数据类型是学习这门语言的第一步。以下是一些基础概念的详细介绍:
一个基础的 C++ 程序通常包括一个或多个头文件引用、一个 main
函数、以及其他函数定义。程序执行从 main
函数开始。
- #include
// 头文件引用 -
- // main函数 - 程序入口点
- int main() {
- std::cout << "Hello, World!" << std::endl; // 输出到控制台
- return 0; // 程序结束
- }
C++ 提供了多种基本数据类型来存储各种类型的数据:
int
, short
, long
, long long
)float
, double
)char
)bool
)- int age = 30; // 整型
- double salary = 4500.50; // 浮点型
- char grade = 'A'; // 字符型
- bool isEmployed = true; // 布尔型
C++ 使用条件语句(如 if
, else
)和循环语句(如 for
, while
)来控制程序的执行流程。
- // 条件语句
- if (age > 18) {
- std::cout << "Adult" << std::endl;
- } else {
- std::cout << "Not Adult" << std::endl;
- }
-
- // 循环语句
- for(int i = 0; i < 5; i++) {
- std::cout << i << " ";
- }
函数是执行特定任务的独立代码块。C++ 中的函数可以有参数,也可以有返回值。
- // 定义一个函数
- int add(int a, int b) {
- return a + b;
- }
-
- // 调用函数
- int result = add(5, 3); // result 将会是 8
整型用于存储整数值。C++ 提供了不同大小的整型,如 int
(通常是 4 字节)、short
(通常是 2 字节)、long
(至少和 int
一样长,通常是 4 或 8 字节)和 long long
(至少 8 字节)。
浮点型用于存储小数。float
(通常是 4 字节)提供了约 6-7 位十进制精度,而 double
(通常是 8 字节)提供了约 15-16 位十进制精度。
字符型 char
用于存储单个字符(如字母或数字)。在 C++ 中,char
占用 1 字节。
布尔型 bool
用于存储真 (true
) 或假 (false
) 值。它通常用于条件测试。
C++ 使用 cin
和 cout
进行标准输入输出操作,它们分别用于从键盘读取输入和将输出写入到控制台。
- int number;
- std::cout << "Enter a number: ";
- std::cin >> number; // 从控制台读取一个整数
- std::cout << "You entered " << number << std::endl;
C++ 的输入输出流(IOStream)库提供了一套面向对象的方式来进行输入输出(I/O)操作。这个库定义了用于读写数据的流对象,包括标准输入输出(cin/cout)、文件输入输出(ifstream/ofstream)等。使用 IOStream 库可以让数据的读写变得更加容易和直观。
std::cout
std::cout
代表“控制台输出”,是用于向标准输出设备(通常是终端或屏幕)写数据的对象。<<
运算符(称为插入运算符)向 std::cout
发送数据。- #include
-
- int main() {
- std::cout << "Hello, World!" << std::endl; // 输出字符串,然后换行
- int age = 25;
- std::cout << "Age: " << age << std::endl; // 输出字符串和变量的值,然后换行
- return 0;
- }
std::cin
std::cin
代表“控制台输入”,是用于从标准输入设备(通常是键盘)读取数据的对象。>>
运算符(称为提取运算符)从 std::cin
提取数据。- #include
-
- int main() {
- int number;
- std::cout << "Enter a number: ";
- std::cin >> number; // 从用户处读取一个整数
- std::cout << "You entered: " << number << std::endl;
- return 0;
- }
std::cerr
用于输出错误信息。与 std::cout
不同的是,std::cerr
不经过缓冲区直接输出,确保了即使程序崩溃,错误信息也能立即显示。- #include
-
- int main() {
- std::cerr << "An error occurred" << std::endl;
- return 0;
- }
std::clog
类似于 std::cerr
,但用于输出日志信息。输出到 std::clog
也是不缓冲的。- #include
-
- int main() {
- std::clog << "Log message" << std::endl;
- return 0;
- }
IOStream 提供了多种方式来格式化输出,例如设置宽度、填充字符和浮点数精度。
- #include
- #include
// 包含iomanip库以使用格式化功能 -
- int main() {
- double pi = 3.14159265358979323846;
- std::cout << "Pi is approximately: " << std::setprecision(5) << pi << std::endl; // 设置精度为5
- std::cout << std::setw(10) << std::setfill('*') << 25 << std::endl; // 设置宽度为10,不足部分用*填充
- return 0;
- }
C++ 的 IOStream 库提供了一个高度灵活和强大的输入输出机制。通过学习使用这些基本的流对象和操作符,你可以轻松地在程序中实现复杂的数据输入输出操作。随着对 C++ 的深入学习,你将会接触到更多高级的 I/O 功能,包括文件操作、流的状态检查和错误处理等。
面向对象编程(Object-Oriented Programming,OOP)是 C++ 的核心特性之一,它允许程序员使用类(class)和对象(object)来模拟现实世界中的实体和行为。面向对象编程的主要概念包括封装、继承和多态。下面将深入讨论类和对象、构造函数和析构函数、以及访问修饰符这几个基本概念。
类(Class):类是一个蓝图或模板,定义了一组具有共同属性和行为的对象的结构和功能。它包含了数据成员(属性)和成员函数(方法)。
对象(Object):对象是根据类定义创建的实例。每个对象都拥有类中定义的属性和方法。对象的创建称为实例化。
- class Car {
- public:
- std::string color;
- void drive() {
- std::cout << "Driving" << std::endl;
- }
- };
-
- int main() {
- Car myCar; // 创建 Car 类的对象 myCar
- myCar.color = "Red"; // 访问属性
- myCar.drive(); // 调用方法
- return 0;
- }
构造函数(Constructor):构造函数是一种特殊的成员函数,它在对象被创建时自动调用。构造函数通常用于初始化对象的属性或执行对象创建时必需的其他操作。构造函数的名称与类名相同,且没有返回类型。
析构函数(Destructor):析构函数也是一种特殊的成员函数,它在对象被销毁时自动调用。析构函数用于执行清理操作,如释放资源、关闭文件等。析构函数的名称是在类名前加上波浪符(~
)。
- class Car {
- public:
- Car() { // 构造函数
- std::cout << "Car is being created" << std::endl;
- }
-
- ~Car() { // 析构函数
- std::cout << "Car is being destroyed" << std::endl;
- }
- };
访问修饰符定义了类成员的访问权限。C++ 中主要有三种访问修饰符:
- class Car {
- private:
- std::string engineNumber; // 私有属性
-
- public:
- std::string color; // 公有属性
- void drive() { // 公有方法
- std::cout << "Driving" << std::endl;
- }
- };
通过面向对象编程,C++ 允许开发者创建模块化和可重用的代码,这些代码能够更准确地模拟复杂的现实世界问题。理解类和对象、构造函数和析构函数以及访问修饰符的工作原理是学习面向对象编程的基础。掌握这些概念将帮助你更有效地使用 C++ 进行软件开发。
继承、多态和封装是面向对象编程(OOP)的三大基本特性,C++ 作为一门支持面向对象的编程语言,也实现了这三个特性。它们使得 C++ 代码更加模块化、易于维护和扩展。下面将分别对这三个概念进行详细讲解:
封装是面向对象编程中的一种将数据(属性)和行为(方法)组合为单一的类(class)单元,并限制对某些组件的直接访问的能力。
private
)或受保护(protected
)来实现,这样这些成员就只能被类的方法或特定的友元类访问。- class Box {
- private:
- double length; // 私有属性
-
- public:
- void setLength(double len) { // 公有方法,用于设置 length 的值
- length = len;
- }
- double getLength(void) { // 公有方法,用于获取 length 的值
- return length;
- }
- };
继承允许我们根据另一个类来定义一个类,这样可以从已有的类继承数据和方法,使代码重用成为可能。
:
后跟访问修饰符(如 public
)和基类名称来实现继承。- class Shape { // 基类
- public:
- void setWidth(int w) {
- width = w;
- }
- void setHeight(int h) {
- height = h;
- }
- protected:
- int width;
- int height;
- };
-
- class Rectangle: public Shape { // 派生类
- public:
- int getArea() {
- return (width * height);
- }
- };
多态性允许我们使用统一的接口来操作不同的基本数据类型或类对象。
virtual
关键字声明的函数)实现多态。当一个类中声明了虚函数,任何继承该类的派生类可以重写该函数,以实现不同的行为。- class Shape {
- public:
- virtual void draw() {
- std::cout << "Drawing a shape" << std::endl;
- }
- };
-
- class Circle: public Shape {
- public:
- void draw() override { // 重写 draw 方法
- std::cout << "Drawing a circle" << std::endl;
- }
- };
-
- void drawShape(Shape& shape) { // 通过引用或指针调用函数,实现多态
- shape.draw();
- }
-
- int main() {
- Shape shape;
- Circle circle;
- drawShape(shape); // 输出 "Drawing a shape"
- drawShape(circle); // 输出 "Drawing a circle"
- return 0;
- }
综上所述,封装、继承和多态是实现面向对象程序设计的三个核心概念。它们使得 C++ 程序更加灵活、易于管理和扩展。
C++ 提供了强大的内存管理能力,包括动态内存分配、指针和引用的使用。理解和掌握这些概念对于编写高效、可靠的 C++ 程序至关重要。
在 C++ 中,动态内存分配允许程序在运行时请求内存,用于存储变量或对象,使用完毕后可以释放这些内存。这种机制提供了灵活的内存使用方式,特别是对于那些在编译时无法确定所需内存大小的情况。
new
用于在堆(heap)上分配内存,delete
用于释放这部分内存。- int* ptr = new int; // 分配一个整数的内存
- *ptr = 5; // 在分配的内存中存储值 5
- delete ptr; // 释放内存
动态分配数组:可以使用 new
分配数组,并使用 delete[]
释放数组。
- int* array = new int[10]; // 动态分配大小为 10 的整型数组
- delete[] array; // 释放数组内存
指针是存储另一个变量的内存地址的变量。通过指针,可以间接访问和操作内存中的数据。
- int var = 10;
- int* ptr = &var; // ptr 存储了 var 的地址
- *ptr = 20; // 通过指针修改 var 的值
引用是另一个变量的别名,它提供了另一种形式的间接访问。引用在创建时必须初始化,且一旦绑定到一个变量,就不能改变绑定到另一个变量。
- int var = 10;
- int& ref = var; // ref 是 var 的引用
- ref = 20; // 修改 ref 同样修改了 var
引用与函数参数:引用经常用作函数参数,允许在不传递对象副本的情况下修改传递给函数的实参。
- void increment(int& value) {
- value++;
- }
*
和 &
)来访问或修改所指向的对象,引用则可以像普通变量一样使用。C++ 的内存管理、指针和引用是该语言强大功能的基础。通过动态内存分配,开发者可以高效利用资源;通过指针和引用,可以灵活地访问和操作内存。然而,这些功能也带来了复杂性和潜在的错误风险,如内存泄漏、野指针等,因此必须谨慎使用,确保正确地分配和释放内存。
RAII(Resource Acquisition Is Initialization)是一种在 C++ 中广泛应用的编程技术和设计哲学,主要用于自动管理资源(如动态分配的内存、文件句柄、网络连接等)的生命周期。RAII 的核心思想是将资源的生命周期与对象的生命周期绑定,通过对象的构造函数获取资源并初始化,通过对象的析构函数释放资源。
资源获取:当一个对象被创建时,它的构造函数会自动执行,RAII 倡导在构造函数中获取并初始化所有必要的资源。
资源释放:当对象的生命周期结束时(比如对象离开作用域),它的析构函数会自动被调用。RAII 通过在析构函数中释放对象持有的资源,确保资源使用完毕后被正确清理。
在 C++ 标准库中,许多容器和智能指针(如 std::vector
, std::string
, std::unique_ptr
, std::shared_ptr
)都遵循 RAII 原则,它们自动管理资源,使得开发者可以更加专注于业务逻辑而不是资源的分配和释放。
- #include
- #include
-
- class MyClass {
- public:
- MyClass() { std::cout << "MyClass created\n"; }
- ~MyClass() { std::cout << "MyClass destroyed\n"; }
- };
-
- int main() {
- // 使用 std::unique_ptr 自动管理 MyClass 的实例
- std::unique_ptr
myObject = std::make_unique(); - // 不需要手动删除 myObject,当 myObject 离开作用域时,其析构函数会自动被调用,资源得到释放
- return 0;
- }
在这个例子中,std::unique_ptr
是一个智能指针,遵循 RAII 原则自动管理 MyClass
实例的生命周期。当 myObject
离开作用域时,MyClass
的析构函数会自动被调用,myObject
指向的动态分配的内存会被释放。
RAII 是 C++ 中非常重要的内存管理和资源管理策略。通过智能地利用对象的构造函数和析构函数,RAII 可以帮助开发者避免资源泄漏、简化代码并提高程序的异常安全性。掌握 RAII 是提高 C++ 编码质量和效率的关键。
STL(Standard Template Library,标准模板库)是 C++ 的一个强大的库,提供了一组通用的模板类和函数,这些模板类和函数可以用来实现常见的数据结构和算法。STL 主要包括三大组件:容器(Containers)、算法(Algorithms)、迭代器(Iterators)。在这里,我们将重点介绍 STL 的几种基本容器:vector
、map
和 set
。
std::vector
是一种序列容器,可以看作一个能够存储动态大小数组的模板类。vector
在尾部添加或删除元素非常高效,但在中间或开始插入或删除元素可能较慢,因为这可能需要移动现有元素。
- #include
- #include
-
- int main() {
- std::vector<int> vec; // 创建一个空的 vector
- vec.push_back(10); // 向 vector 中添加元素
- vec.push_back(20);
-
- std::cout << "vec: ";
- for(int i : vec) {
- std::cout << i << " "; // 遍历 vector 并打印元素
- }
- std::cout << std::endl;
-
- return 0;
- }
std::map
是一种关联容器,以键值对的形式存储元素,其中每个键都是唯一的,且每个键映射到一个值。map
内部通常实现为红黑树,提供了对元素的有序存储和对键的快速查找能力。
- #include
- #include
-
- int main() {
- std::map
int> ageMap; // 创建一个空的 map - ageMap["Alice"] = 30; // 向 map 中添加元素
- ageMap["Bob"] = 25;
-
- std::cout << "Bob's age: " << ageMap["Bob"] << std::endl; // 通过键访问并打印元素
-
- return 0;
- }
std::set
也是一种关联容器,它存储唯一的元素,没有重复的值。set
的内部实现也是基于红黑树,保证了元素的有序性和快速查找。
- #include
- #include
-
- int main() {
- std::set<int> mySet; // 创建一个空的 set
- mySet.insert(10); // 向 set 中添加元素
- mySet.insert(20);
- mySet.insert(10); // 重复的元素不会被添加
-
- std::cout << "mySet: ";
- for(int elem : mySet) {
- std::cout << elem << " "; // 遍历 set 并打印元素
- }
- std::cout << std::endl;
-
- return 0;
- }
STL 的容器提供了强大而灵活的数据结构,以支持各种程序设计需求。vector
、map
和 set
是最常用的几种容器类型,它们各自有不同的用途和性能特点:
vector
:动态数组,适用于需要频繁访问元素的场景。map
:键值对集合,适用于需要根据键快速查找值的场景。set
:唯一元素集合,适用于需要快速查找、插入和删除且不重复的元素的场景。熟练使用这些容器将有助于提高编程效率和代码质量。
STL(Standard Template Library,标准模板库)是 C++ 中提供的一组模板类和函数,旨在提供常用的数据结构和算法。除了容器外,STL 还包括迭代器、算法和函数对象,这些组件共同构成了 STL 的核心。下面是对这些组件的详细讲解:
迭代器是一种访问容器中元素的对象,它提供了一种方式来顺序访问容器中的元素,而不需要了解容器的内部结构。迭代器类似于指针,但是设计得更为通用。
input iterators
, output iterators
, forward iterators
, bidirectional iterators
, 和 random access iterators
。- #include
- #include
-
- int main() {
- std::vector<int> vec{1, 2, 3, 4, 5};
- for(std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
- std::cout << *it << " ";
- }
- std::cout << std::endl;
- return 0;
- }
STL 提供了一系列在容器上执行操作的模板函数,如排序、查找、复制、修改等。这些算法是通用的,可以用于不同类型的容器。
count
, find
),修改序列操作(如 copy
, replace
),排序和相关操作(如 sort
, binary_search
),以及数值算法(如 accumulate
, partial_sum
)。- #include
- #include
- #include
-
- int main() {
- std::vector<int> vec{4, 2, 5, 1, 3};
- std::sort(vec.begin(), vec.end()); // 对 vec 进行排序
-
- for(int elem : vec) {
- std::cout << elem << " ";
- }
- std::cout << std::endl;
- return 0;
- }
函数对象是重载了函数调用操作符 ()
的任何对象。STL 中的许多算法都可以接受函数对象作为参数,这允许程序员自定义操作行为。
- #include
- #include
- #include
-
- class Compare {
- public:
- bool operator()(int a, int b) {
- return a < b; // 升序排序
- }
- };
-
- int main() {
- std::vector<int> vec{4, 2, 5, 1, 3};
- std::sort(vec.begin(), vec.end(), Compare()); // 使用 Compare 函数对象
-
- for(int elem : vec) {
- std::cout << elem << " ";
- }
- std::cout << std::endl;
- return 0;
- }
STL 的迭代器、算法和函数对象是 C++ 中实现高效和灵活程序设计的重要工具。通过迭代器,可以抽象地访问容器中的元素;算法提供了一套广泛的操作容器的方法;而函数对象则允许自定义这些操作的行为。熟练地使用这些组件,可以极大地提高编程的效率和代码的复用性。