文章目录
- [知识点 1:C++ 的概述](#知识点 1:C++ 的概述)
-
- [1. C++的特征](#1. C++的特征)
- [2. C++ 程序的编辑、编译和执行](#2. C++ 程序的编辑、编译和执行)
- [3. 第一个 C++ 源程序](#3. 第一个 C++ 源程序)
- [4. 面向对象程序设计思想](#4. 面向对象程序设计思想)
-
- [4.1 面向对象程序设计思想初始](#4.1 面向对象程序设计思想初始)
- [4.2 面向对象程序设计思想的核心](#4.2 面向对象程序设计思想的核心)
- [知识点 2:C++ 对 C 的扩展](#知识点 2:C++ 对 C 的扩展)
-
- [1. 作用域访问运算符 `::`](#1. 作用域访问运算符
::
) -
- [1.1 全局变量和局部变量](#1.1 全局变量和局部变量)
- [1.2 作用域为类域或名称空间域](#1.2 作用域为类域或名称空间域)
- [2. 名称空间域](#2. 名称空间域)
-
- [2.1 创建命名空间](#2.1 创建命名空间)
- [2.2 名称空间域成员访问](#2.2 名称空间域成员访问)
- [2.3 多文件命名空间创建](#2.3 多文件命名空间创建)
- [1. 作用域访问运算符 `::`](#1. 作用域访问运算符
- [知识点 3:语法增强](#知识点 3:语法增强)
-
- [1. 数据类型增强](#1. 数据类型增强)
- [知识点 4:函数重载和默认参数](#知识点 4:函数重载和默认参数)
-
- [1. 函数重载](#1. 函数重载)
- [2. 默认参数](#2. 默认参数)
- [知识点 5:内存管理](#知识点 5:内存管理)
-
- [2. `new` 和 `malloc` 的区别](#2.
new
和malloc
的区别)
- [2. `new` 和 `malloc` 的区别](#2.
- [知识点 6:函数的占位参数](#知识点 6:函数的占位参数)
- [知识点 7:内联函数](#知识点 7:内联函数)
-
- [1. 内联函数的定义](#1. 内联函数的定义)
- [2. 内联函数的编译规则](#2. 内联函数的编译规则)
- [3. 内联函数和普通函数的区别](#3. 内联函数和普通函数的区别)
- [知识点 8:C++中的输入输出](#知识点 8:C++中的输入输出)
-
- [1. 继承 C 语言中的输入输出](#1. 继承 C 语言中的输入输出)
- [2. C++ 新增标准输入输出](#2. C++ 新增标准输入输出)
- [知识点 9:字符串类](#知识点 9:字符串类)
- [知识点 10:C++ 内存管理](#知识点 10:C++ 内存管理)
-
- [1. C 语言中的内存管理方式](#1. C 语言中的内存管理方式)
- [2. C++ 内存管理](#2. C++ 内存管理)
- [知识点 11:函数返回值为引用](#知识点 11:函数返回值为引用)
- [知识点 12:引用与指针的区别](#知识点 12:引用与指针的区别)
知识点 1:C++ 的概述
1. C++的特征
C++ 是对 C 的扩展,语言在 C 语言的基础上添加了面向对象编程和泛型编程的支持。
- C++ 继承 C 语言的思想:具备 C 语言面向过程的思想,语言高效、简洁,具有可移植性。
- C++ 具备面向对象程序设计思想。
- 模板支持的泛型编程。
2. C++ 程序的编辑、编译和执行
由于 C++ 继承了 C 语言的特性,C 语言程序可以作为 C++ 程序。在 Linux 系统中,GNU 工具中提供了 C++ 编译器 g++
,整个程序的编译过程依然分为 4 个阶段:
- 整体编译 :
g++ 源程序文件
可以使用-o
指定输出可执行文件名称,如果未指定则默认生成可执行文件a.out
。
-
预处理阶段:实现预处理指令的执行,头文件的展开、宏定义的替换、语句的选择编译。
bashg++ -E hello.c -o hello.i
-
编译阶段:实现预处理后程序语法的检测,并生成汇编指令。
bashg++ -S hello.i -o hello.s
-
汇编阶段:将汇编指令翻译为二进制机器指令。
bashg++ -C hello.s -o hello.o
-
链接阶段 :将程序中所有的
.o
文件进行链接、依赖库链接和启动程序连接。bashg++ hello.o -o hello
3. 第一个 C++ 源程序
cpp
#include <iostream> /* 添加头文件:标准库头文件(提供标准输入输出流) */
using namespace std; /* 名称空间声明 */
int main()
{
cout << "hello world" << endl; /* 标准输出流和换行 */
return 0;
}
- C++ 源程序后缀 :可以使用
.c
、.cxx
、.cpp
,一般情况将源程序文件后缀设置为.cpp
,可移植性更好。 - 头文件的包含 :
#include <iostream>
。 - namespace:用于避免同一个程序中的多个同名变量和函数的访问冲突。
- cout 和 endl :
cout
是标准输出流,定义在std
命名空间中;endl
是换行标识,同时刷新缓冲区。
4. 面向对象程序设计思想
4.1 面向对象程序设计思想初始
- 面向过程程序设计思想:以解决问题的思路为步骤,按照步骤先后顺序依次执行逐一解决问题的过程。核心是功能分解,自顶向下,逐层细化(程序 = 数据结构 + 算法)。
- 面向对象程序设计思想:即 OOP 技术。任何类对象都具有一定的属性和操作行为,属性抽象为数据类型变量,行为抽象为函数及其算法。对象 = 数据结构 + 算法;程序 = 对象 + 对象 + ......
4.2 面向对象程序设计思想的核心
- 封装:将对象的属性抽象为数据类型的成员变量,对象的行为抽象为成员函数,并使用访问权限修饰符封装。
- 继承:表示类与类之间的关系,新构造类对象继承原有类对象的属性和行为,有效实现代码重用,避免冗余。
- 多态:一个接口,多种方法,在程序运行过程中决定接口的具体行为。
知识点 2:C++ 对 C 的扩展
1. 作用域访问运算符 ::
C++ 增加了作用域访问运算符 ::
,可修饰函数和变量的作用域,实现对不同作用域下同名成员变量和函数的访问。语法格式:
cpp
作用域::函数和变量符号
- 作用域可以是全局作用域、局部作用域、命名空间域和类域。
- 函数和变量符号可以是 C 函数和变量、类成员函数和变量以及命名空间域成员函数和变量。
1.1 全局变量和局部变量
当作用域和作用域运算符省略时,模块内定义的局部变量覆盖全局变量。
cpp
#include <stdio.h>
int a = 1; /* 定义全局变量 */
int main()
{
int a = 3; /* 局部变量覆盖全局变量 */
printf("a = %d\n", a);
printf("::a = %d\n", ::a); /* 访问全局变量 */
}
1.2 作用域为类域或名称空间域
cpp
#include <stdio.h>
int a = 1;
namespace myspace {
int a = 4; /* 变量 a 的作用域为 myspace 命名空间 */
}
int main()
{
int a = 3;
printf("a = %d\n", a);
printf("::a = %d\n", ::a); /* 访问全局变量 */
printf("myspace::a = %d\n", myspace::a); /* 访问 myspace 中的变量 */
}
2. 名称空间域
将符号常量、变量、函数、结构体、枚举等数据量使用关键字 namespace
的名称空间域进行封装,解决程序中同名导致的访问冲突问题。
2.1 创建命名空间
- 有名命名空间:
cpp
namespace myspace {
int a = 5;
void show() {
printf("myspace -> a = %d\n", a);
}
}
- 无名命名空间 :无名命名空间中的成员只能在当前文件中访问,相当于使用
static
修饰。
cpp
namespace {
int a = 4;
int b = 5;
}
2.2 名称空间域成员访问
通过作用域访问运算符访问或声明命名空间后直接访问。
cpp
std::cout << "namespace" << std::endl; /* 访问 std 名称空间域中的 cout 和 endl */
using namespace std; /* 声明名称空间域 */
cout << "namespace" << endl; /* 已声明的符号可直接访问 */
2.3 多文件命名空间创建
在实际应用中,可能多个文件中的成员属于同一个名称空间域。注意以下几点:
- 头文件中不能定义变量和函数,只能声明。
- 名称空间域中的变量只能在源文件中定义,作用域仅限于该文件。
cpp
namespace myspace {
void test(void); /* 在头文件中声明 */
}
知识点 3:语法增强
1. 数据类型增强
C++ 提供了更严格的类型检查和更丰富的数据类型支持,例如 bool
类型。
cpp
bool flag = true; /* 在 C++ 中直接支持 bool 类型 */
知识点 4:函数重载和默认参数
1. 函数重载
C++ 支持同名但参数不同的函数,这称为函数重载。不同函数根据参数类型、数量或顺序进行区分。
cpp
int add(int a, int b) { return a + b; }
float add(float a, float b) { return a + b; }
2. 默认参数
在函数声明时,可以为形参设置默认值,调用函数时如果没有传递实参,则使用默认值。
cpp
void printVal(int a = 0, int b = 0) {
printf("a = %d, b = %d\n", a, b);
}
知识点 5:内存管理
C++ 提供了 new
和 delete
操作符来管理动态内存分配和释放,与 C 语言中的 malloc
和 free
相对。与 C 语言不同,new
自动推导分配空间的大小,并在失败时抛出异常。
cpp
int *p = new int; /* 动态分配单个 int 类型元素存储空间 */
delete p; /* 释放动态分配的内存 */
2. new
和 malloc
的区别
在 C++ 中,new
和 malloc
都用于动态内存管理,但它们之间有一些重要区别:
-
属性不同:
new
和delete
是 C++ 的运算符,由编译器支持;可以重载。malloc
和free
是 C 语言的库函数,需要包含头文件<stdlib.h>
;无法重载。
-
使用方式不同:
-
malloc
动态开辟内存时,需要显示指定申请的内存大小,并返回void*
类型指针,通常需要进行类型转换。cppint *malloc_p = (int *)malloc(4); /* 开辟 4 字节的空间 */ free(malloc_p);
-
new
动态开辟内存时,自动分配适合数据类型大小的内存,并返回相应类型的指针。cppint *new_p = new int; /* 根据 int 类型分配内存 */ delete new_p;
-
-
存储内存位置不同:
malloc
所申请的内存一定位于堆区。new
的内存空间称为自由存储区,默认使用堆区实现自由存储区。自由存储区是 C++ 动态内存分配和释放的概念,实际存储位置由new
实现决定。
-
返回类型不同:
malloc
返回void*
,需要进行强制类型转换。new
返回指定类型的指针,无需强制类型转换。
-
分配失败处理:
malloc
失败时返回NULL
,需要手动检查是否为空。new
失败时抛出bad_alloc
异常。
-
构造与析构:
malloc
仅分配内存,不调用构造函数,需要手动初始化对象。new
会自动调用对象的构造函数,delete
会自动调用析构函数。
-
内存扩展:
malloc
可以使用realloc
来扩展已经分配的内存。new
没有内存扩展机制,必须重新分配内存并手动迁移数据。
知识点 6:函数的占位参数
所谓的函数占位参数,指的是在函数定义时,形参列表中有些参数只定义了数据类型而没有定义形参变量名,这些参数仅用于占位。例如:
cpp
void func(int a, int = 3) /* 第二个参数是占位参数,默认值为 3 */
{
printf("a = %d\n", a);
}
占位参数可用于区分前置和后置递增/递减运算符的重载。
知识点 7:内联函数
1. 内联函数的定义
内联函数类似于 C 语言中的宏定义。内联函数通过在函数前加上 inline
关键字来声明,编译器将尽量将其替换为内联代码,减少函数调用的开销。
cpp
inline int func(int a) {
return a++;
}
类中的成员函数如果定义在类的内部,默认会被视为内联函数。
cpp
class Demo {
public:
int func(int a) {
return a++; /* 类内部的函数自动为内联函数 */
}
};
2. 内联函数的编译规则
虽然 inline
是建议编译器将函数作为内联处理,但编译器根据以下规则决定是否真正将函数内联:
- 函数体不能包含任何形式的循环语句。
- 函数体不能有过多的条件判断语句。
- 函数体不能过于庞大。
- 不能对函数进行取址操作。
3. 内联函数和普通函数的区别
- 占用更多存储空间:内联函数在编译时将函数体替换到调用点,因此会占用更多的代码空间。
- 提高执行效率:内联函数省去了函数调用时的压栈、跳转及返回操作,从而提升执行效率。内联函数本质上是通过"以空间换时间"来提高性能。
知识点 8:C++中的输入输出
1. 继承 C 语言中的输入输出
C++ 继承了 C 语言的输入输出机制,可以直接使用标准 C 库中的 printf
、scanf
等函数实现输入输出。
2. C++ 新增标准输入输出
-
标准输出流
std::cout
:C++ 提供了
std::cout
作为标准输出流,通过<<
重定向运算符实现输出。cppstd::cout << "Hello, World!" << std::endl; /* 输出字符串并换行 */
注意:
- 多个数据输出时,可以使用多个
<<
进行链接。 - 数据可以是变量或常量。
std::endl
是换行符,等价于 C 语言中的\n
,同时会刷新缓冲区。
- 多个数据输出时,可以使用多个
-
标准输入流
std::cin
:
std::cin
作为标准输入流,通过>>
运算符实现数据输入。cppint a; std::cin >> a; /* 从标准输入读取数据赋值给变量 a */
知识点 9:字符串类
在 C++ 中,字符串可以通过字符数组存储,也可以使用 C++ 标准库中的 std::string
类来处理。
- C 风格字符串:仍然可以使用 C 语言的字符数组存储字符串。
std::string
类 :C++ 中新增的字符串类提供了更多方便的操作方法和运算符重载,如+
进行字符串连接,[]
访问字符等。
+
:用于连接两个字符串。=
:用于赋值操作,相当于 C 语言中的strcpy
。+=
:在原有字符串后追加新字符串,相当于 C 语言中的strcat
。
知识点 10:C++ 内存管理
1. C 语言中的内存管理方式
C 语言中的内存管理包括静态分配和动态分配:
- 静态分配:全局变量、局部变量、常量的存储位置和生命周期是由编译器管理的。
- 动态分配 :使用
malloc
、calloc
、realloc
函数动态分配内存,在使用完毕后需要调用free
释放内存。
c
void *malloc(size_t size);
void free(void *ptr);
2. C++ 内存管理
C++ 继承了 C 语言的内存管理方式,同时新增了使用 new
和 delete
运算符进行动态内存管理:
-
使用
new
和delete
:new
动态分配内存,delete
释放内存。new
自动调用对象的构造函数,delete
自动调用析构函数。
cppint *p = new int; /* 分配单个 int 类型的空间 */ delete p; /* 释放内存 */
-
new 和 malloc 的区别:如前面章节中详细介绍。
知识点 11:函数返回值为引用
在 C++ 中,函数可以返回引用类型。这允许函数返回一个对现有变量的引用,而不是一个新的值。
cpp
int& getValue() {
static int a = 10;
return a; /* 返回静态变量的引用 */
}
- 引用返回值的优点:可以避免不必要的内存拷贝,提高程序效率。
- 注意事项:返回的引用变量必须是静态的或全局的,不能是局部变量,否则会出现非法访问。
知识点 12:引用与指针的区别
引用和指针在 C++ 中有相似的作用,但它们有明显的区别:
- 引用是别名,不占用额外的存储空间,定义时必须初始化且不能更改引用的对象。
- 指针是一个存储地址的变量 ,可以为空(
NULL
),且可以在运行时指向不同的对象。 - 访问方式 :引用通过变量名直接访问,而指针需要通过
*
运算符进行解引用。
cpp
int a = 10;
int &ref = a; /* 引用 */
int *ptr = &a; /* 指针 */
到此为止,我们
完整覆盖了最初的 C++ 知识点内容。