C++ 基础核心知识
C++作为一门兼具高效性和灵活性的编程语言,是系统开发、游戏引擎、嵌入式编程等领域的核心工具。本文将从变量类型、指针与引用、核心关键字、数据类型、宏与高级修饰符、函数指针等高频基础知识点入手,夯实编程基础。
一、变量的三类核心形态:局部、静态局部、全局
变量是程序存储数据的基本单元,根据作用域、生命周期和存储位置的差异,可分为局部变量、静态局部变量和全局变量三类,其特性和使用场景各有侧重,是理解C++内存管理的基础。
1. 核心特性对比
| 局部变量 | 当前函数/代码块内 | 函数调用时创建,返回时销毁 | 未赋值则值随机 | 栈区(stack) | 存取速度快,随用随弃,无内存泄漏风险 |
| 静态局部变量 | 当前函数内部(外部不可访问) | 程序启动至结束 | 仅初始化一次,默认值0 | 数据段/BSS段 | 保留上次调用结果,函数内的“全局状态” |
| 全局变量 | 整个程序内 | 程序启动至结束 | 默认初始化为0 | 数据段/BSS段 | 跨函数/文件共享,易导致程序耦合度升高 |
2. 实用场景解析
- 局部变量:最常用的变量类型,适合存储临时数据,比如循环计数器、函数内部的中间计算结果。例如遍历数组时的索引变量int i,函数内临时存储计算值的int temp,用完自动释放栈内存,使用安全且无冗余开销。
- 静态局部变量:适合需要“记忆状态”的场景,比如统计函数调用次数、递归深度控制、单例模式的懒汉式实现。例如:
void countCall() {
static int count = 0; // 仅首次调用初始化,后续调用保留值
cout << "调用次数:" << ++count << endl;
}
// 多次调用依次输出1、2、3…
- 全局变量:用于存储整个程序需共享的全局数据,比如系统配置信息、全局缓冲区、跨模块的状态标识。但需谨慎使用,过多全局变量会导致程序耦合度升高、难以维护和调试;使用时可添加清晰注释,必要时用static修饰限制在当前文件内,避免跨文件命名冲突。
二、指针与引用:C++的核心内存操作符
指针和引用是C++区别于其他高级语言的核心特性,二者均用于间接操作变量,实现内存的灵活访问,但在语法、本质、功能和使用场景上差异显著,正确区分是避免内存错误的关键。
1. 核心区别总结
| 本质 | 存储变量内存地址的独立变量,有自己的内存空间 | 变量的别名,无独立内存空间,与绑定对象共享地址 |
| 初始化 | 可延迟初始化,可设为nullptr(空指针) | 必须在定义时初始化,且不能绑定空值/无效对象 |
| 重新绑定 | 可随时重新指向其他同类型对象 | 一旦绑定对象,生命周期内不可修改绑定关系 |
| 操作方式 | 需通过解引用符(*)访问目标值,指针移动用-> | 直接操作,无需解引用,语法与普通变量一致 |
| 内存占用 | 32位系统4字节,64位系统8字节(与地址长度一致) | 无额外内存占用,编译期处理,与绑定对象大小一致 |
| 安全性 | 可能出现野指针/悬空指针,使用前必须判空 | 无空引用,只要绑定有效对象则使用安全,无需判空 |
| 支持操作 | 可进行指针算术运算(如p++)、多级指针(int**) | 不支持算术运算,无多级引用 |
2. 适用场景
-
指针的适用场景:
- 动态内存分配(new/delete):例如创建动态数组int* arr = new int[10]、自定义类的动态对象;
- 遍历复杂数据结构(链表、树、图):通过指针移动访问下一个节点node->next,实现灵活的内存遍历;
- 处理可选参数:允许传递nullptr表示“无参数”,适配多场景函数调用;
- 多级间接访问:如指针的指针int** p,适用于二维数组、函数内修改外部指针;
- 函数返回多个值:通过指针将结果输出到函数外部。
-
引用的适用场景:
- 函数参数传递:尤其是大型对象(如自定义类实例、std::string、std::vector),避免拷贝开销,提升程序效率。例如void printString(const string& s),直接引用原对象而非创建拷贝;
- 函数返回值优化:实现链式调用(如cout << a << b,operator<<返回ostream&),避免返回值拷贝;
- 类成员引用:必须在构造函数初始化列表中绑定,确保引用的生命周期与类对象一致,适用于类的关联属性;
- 替代指针简化代码:在无需重新绑定的场景下,用引用替代指针,让代码更简洁、安全。
3. 核心注意事项
- 指针使用前必须判空(if (p != nullptr)),避免野指针(未初始化)、悬空指针(指向已释放内存)导致程序崩溃;
- 引用不能绑定临时变量(如int& a = 10;非法),除非是const引用(const int& a = 10;合法,编译器会创建临时对象);
- 动态内存分配的指针需手动释放(delete/delete[]),否则会造成内存泄漏;建议优先使用智能指针(std::unique_ptr/std::shared_ptr)替代裸指针。
三、核心关键字
C++的关键字是控制程序语法规则、内存行为、访问权限的核心,其中const、static是最常用且易混淆的基础关键字,掌握其不同场景的语义,是编写规范、高效C++代码的前提。
1. const:常量修饰符,保证只读特性
const的核心语义是只读,可修饰变量、指针、引用、成员函数、函数参数等,是保证程序安全性、防止意外修改的重要工具,其修饰对象不同,语义也略有差异。
- 修饰普通变量:const int max = 100,变量值初始化后不可修改,必须在定义时初始化;
- 修饰指针:分为两种场景,核心看const与*的位置:
- 指针常量(int* const p):const修饰指针本身,指针的指向不可修改,但指向的值可修改;
- 指向常量的指针(const int* p):const修饰指向的值,值不可修改,但指针的指向可修改;
- 修饰引用:const int& ref,引用的对象为只读,防止通过引用修改原对象,是函数参数传递的常用方式;
- 修饰类成员函数:void show() const,函数后加const,表示该函数不修改类的任何非静态成员变量,是类的常成员函数;
- 修饰函数参数:void func(const int& x),防止函数内部修改传入的参数值,同时避免拷贝开销。
2. static:静态修饰符,控制生命周期与作用域
static主要用于控制变量/函数的生命周期、作用域和访问权限,在不同场景下作用不同,核心分为“全局/函数内”和“类内”两大使用场景。
- 静态局部变量(函数内):延长生命周期至程序结束,作用域仍限于当前函数内,仅初始化一次;
- 静态全局变量/函数(文件内):将作用域限制在当前文件内,实现“文件私有”,避免跨文件命名冲突;函数默认具有外部链接属性,加static后变为内部链接;
- 类的静态成员变量:属于类而非某个对象,所有类实例共享同一份数据,需在类外单独初始化(int ClassName::var = 0),存储在数据段;
- 类的静态成员函数:属于类而非对象,无隐式的this指针,只能访问类的静态成员(变量/函数),可通过类名直接调用(ClassName::func()),无需创建对象。
3. new/delete 与 malloc/free:内存管理核心对比
new/delete是C++原生的内存操作运算符,malloc/free是C标准库的内存管理函数,二者均用于动态内存分配,但在语法、功能、特性上差异显著,C++开发中优先使用new/delete替代malloc/free。
| 本质 | C++语言原生运算符,属于语法层面 | C标准库普通函数,需引入头文件<cstdlib> |
| 内存计算 | 自动计算所需内存大小,无需手动指定 | 需开发者手动计算并传入内存字节数(如malloc(4*10)) |
| 初始化/析构 | new调用对象构造函数完成初始化,delete调用析构函数释放资源 | 仅分配/释放原始内存,不调用构造/析构函数,内存内容为随机值 |
| 返回值类型 | 带类型的指针,无需强制类型转换(如int* p = new int) | 返回void*类型指针,必须强制类型转换后使用(如int* p = (int*)malloc(4)) |
| 失败处理 | 分配失败时抛出bad_alloc异常,可通过try-catch捕获 | 分配失败时返回NULL,需手动判空检查 |
| 重载支持 | 可自定义重载,实现自定义内存池、内存分配策略 | 不可重载,分配策略固定 |
| 数组处理 | 有专门的数组版本new[]/delete[],匹配数组的构造/析构 | 无专门数组版本,需手动计算数组总字节数,且不处理数组对象的析构 |
| 类对象支持 | 完美支持类对象的动态创建/释放,是C++面向对象的核心支撑 | 仅能分配类对象的内存空间,无法初始化对象,不支持面向对象开发 |
| 示例 | 单个对象:int* p = new int(10); delete p;数组:int* arr = new int[5]; delete[] arr;类对象:Test* t = new Test(); delete t; | 单个变量:int* p = (int*)malloc(4); free(p);数组:int* arr = (int*)malloc(4*5); free(arr); |
4. 其他基础常用关键字对比
| typedef | 编译阶段的类型别名定义 | 有类型检查,提升代码可读性,支持自定义复杂类型 | typedef int MyInt; typedef vector<int> IntVec; |
| nullptr | C++11空指针关键字 | 类型安全,仅能隐式转换为指针类型,无二义性 | int* p = nullptr; |
| NULL | 宏定义(通常为0或(void*)0) | 可转换为整数类型,可能引发函数调用二义性 | int* p = NULL; |
使用建议:C++开发中优先使用new/delete替代malloc/free,优先使用nullptr替代NULL,避免类型二义性和内存管理错误。
四、数据类型与强制类型转换
C++是强类型语言,数据类型决定了变量的内存大小、取值范围和可执行操作;强制类型转换用于实现不同类型间的转换,C++提供了类型安全的转换运算符,替代C语言的隐式转换,明确转换意图。
1. 基本数据类型
C++的基本数据类型分为整型、浮点型、字符型、布尔型,其中整型遵循**“最小长度规则”**,具体长度可通过sizeof运算符查询,不同平台可能略有差异,核心类型如下:
- 整型:short(至少16位/2字节)、int(至少与short等长,通常32位/4字节)、long(至少32位/4字节)、long long(至少64位/8字节);
- 无符号整型:在整型前加unsigned,如unsigned int、unsigned long,不存储负数,最大值为对应有符号整型的2倍,适合存储计数类、索引类数据;
- 浮点型:float(单精度,4字节)、double(双精度,8字节)、long double(扩展精度,≥8字节),用于存储小数,双精度是开发中的默认选择;
- 字符型:char(1字节)、wchar_t(宽字符,2/4字节),用于存储单个字符,char可分为有符号(默认)和无符号(unsigned char);
- 布尔型:bool,取值为true(1)或false(0),用于逻辑判断。
注意:可通过<climits>、<cfloat>头文件查看不同数据类型的取值范围,如INT_MAX(int的最大值)、FLT_MAX(float的最大值)。
2. 强制类型转换
C++提供4种类型安全的强制转换运算符,替代C语言的(类型)变量隐式转换,明确转换意图,减少转换错误,不同运算符适用于不同场景,不可混用。
| static_cast | 基本类型转换、上行转换(派生类→基类)、非const转非const | 编译期检查,无运行时类型检查 | 较高(需开发者保证转换合理性) |
| dynamic_cast | 含虚函数的类层次结构转换,主要用于下行转换(基类→派生类) | 运行期类型检查,基于RTTI(运行时类型信息) | 最高(转换失败返回nullptr/抛出异常) |
| reinterpret_cast | 任意指针/引用之间的转换、指针与整数的转换 | 编译期处理,仅做二进制位拷贝,不改变数据 | 最低(平台移植性差,慎用) |
| const_cast | 移除变量的const或volatile属性 | 仅作用于指针/引用,不能直接修饰变量 | 中等(不可修改原常量值,否则行为未定义) |
示例:
// static_cast:基本类型转换
int a = 10;
double b = static_cast<double>(a) / 3; // 3.33333
// dynamic_cast:类层次转换
class Base { virtual void func() {} };
class Derived : public Base {};
Base* p = new Derived;
Derived* d = dynamic_cast<Derived*>(p); // 转换成功
// const_cast:移除const属性
const int c = 20;
int* pc = const_cast<int*>(&c);
// *pc = 30; // 非法:修改原常量,行为未定义
// reinterpret_cast:指针类型强制转换
int x = 100;
int* px = &x;
char* pc = reinterpret_cast<char*>(px);
五、宏与高级修饰符:易混淆核心概念辨析
在C++开发中,#define宏、inline、constexpr、volatile、extern是高频易混淆的语法元素,其中#define是C语言兼容的预处理语法,其余均为C++的高级修饰符,掌握其差异是编写高效、安全代码的关键。
1. #define 与 inline:宏替换 vs 内联函数
二者均试图减少函数调用开销,但实现原理、阶段和安全性天差地别,inline是C++推荐的函数优化手段,优先用inline替代#define定义宏函数。
| 处理阶段 | 预处理阶段(编译前),纯字符串替换 | 编译阶段,编译器做代码展开优化 |
| 类型检查 | 无任何类型检查,易因参数类型导致隐式错误 | 严格的参数/返回值类型检查,符合C++语法规则 |
| 作用域 | 全局有效,需用#undef手动终止作用域 | 遵循函数作用域,可受namespace/类限制 |
| 内存特性 | 无栈帧开销,但重复替换会增加代码段体积(代码膨胀) | 无函数调用栈帧开销,编译器智能判断是否展开(复杂逻辑自动放弃内联) |
| 支持特性 | 不支持递归、默认参数、函数重载 | 支持递归、默认参数、函数重载,与普通函数一致 |
| 坑点 | 缺少括号易出逻辑错误:#define MUL(a,b) a*b,调用MUL(2+3,4)展开为2+3*4=14(非预期20) | 仅适用于短逻辑、高频调用的函数(如getter/简单计算),复杂函数内联无意义 |
| 示例 | #define ADD(a,b) ((a)+(b))(加括号避免错误) | inline int add(int a, int b) { return a + b; } |
2. #define 与 const:宏常量 vs 常量变量
二者均用于定义“不可变值”,但const是C++强类型的常量修饰符,#define是无类型的预处理替换,生产环境优先使用const替代#define定义常量。
| 类型属性 | 无类型,仅做字符串替换,编译器无感知 | 有明确类型,编译器严格进行类型检查 |
| 处理阶段 | 预处理阶段直接替换,不参与编译过程 | 编译阶段处理,作为常量变量存入内存(数据段只读区域) |
| 作用域 | 全局有效,跨文件可见,需#undef终止 | 局部const:作用域为代码块/函数;全局const:默认文件内私有(可通过extern扩展) |
| 内存占用 | 不分配内存,编译时直接替换为字面量 | 分配内存,有唯一内存地址,可取址(&const_var) |
| 类中使用 | 无法作为类成员(预处理阶段无类概念) | 可作为类成员,非静态const需在构造函数初始化列表初始化,静态const需类外初始化 |
| 示例 | #define PI 3.1415926 #define MAX_LEN 1024 | const double PI = 3.1415926; const int MAX_LEN = 1024; |
3. constexpr 与 const:编译期常量 vs 运行期只读变量
C++11引入constexpr,强化了“编译期常量”的语义,弥补了const“只读但未必是编译期常量”的缺陷,constexpr是更强的const。
| 核心语义 | 初始化后值不可修改,值可运行期确定 | 值必须在编译阶段计算完成,运行期不可修改 |
| 初始化值 | 可接受编译期常量(如const int a=10)或运行期常量(如const int a=rand()) | 必须是编译期可计算的常量表达式(字面量、constexpr变量、constexpr函数返回值) |
| 内存占用 | 分配内存(数据段),有内存地址,可取址 | 编译期直接替换为字面量,通常不分配内存;若取址则分配只读内存 |
| 函数修饰 | 不可修饰函数,仅能修饰类成员函数为const | 可修饰constexpr函数,要求函数体为编译期可执行的简单逻辑(无循环/动态内存) |
| 类中使用 | 静态const成员需类外初始化;非静态const成员需构造函数初始化列表初始化 | 静态constexpr成员可直接在类内初始化(C++11及以上),无需类外定义 |
| 适用场景 | 定义运行期只读变量(函数内临时只读值、类实例的只读属性) | 定义编译期确定的常量(数组大小、模板参数、编译期计算、硬件寄存器地址) |
| 示例 | const int a = rand();(合法,运行期常量) | constexpr int a = 10+20; constexpr int arr[a];(标准合法,编译期确定数组大小) |
4. volatile:易变变量修饰符,禁止编译器优化
volatile是C++中容易被忽略但至关重要的修饰符,核心语义是**“告诉编译器:该变量的值可能被程序外部因素修改,禁止对其进行任何优化”**,确保每次访问都直接读取内存,而非缓存到寄存器。
核心特性
适用场景
- 嵌入式开发:硬件寄存器操作(寄存器地址固定,值可能被硬件/外设修改);
- 中断处理程序:中断服务函数中修改的变量,需防止编译器优化;
- 多线程开发:多线程共享的变量,保证内存可见性(需配合内存屏障);
- 信号处理函数:信号处理中修改的全局变量,避免编译器优化为死循环。
示例
// 嵌入式串口接收寄存器操作(寄存器地址固定,值由硬件修改)
#define UART_RX_REG 0x12345678 // 串口接收寄存器物理地址
volatile int* rx_reg = (volatile int*)UART_RX_REG;
void read_uart_data() {
while (*rx_reg == 0); // 循环等待寄存器值变化(禁止编译器优化为死循环)
int data = *rx_reg; // 直接读取内存中的寄存器值,获取硬件数据
}
5. extern 与 static:作用域与链接属性控制(反向关键字)
二者均用于控制变量/函数的链接属性和跨文件访问性,是C++模块化开发的核心修饰符,作用完全相反:extern实现跨文件共享,static实现文件/作用域私有。
| 核心作用 | 声明跨文件可见的变量/函数,指示编译器“去其他文件找定义” | 限制变量/函数的作用域为当前文件,禁止跨文件访问,实现“文件私有” |
| 链接属性 | 外部链接:多个文件可共享同一变量/函数实体 | 内部链接:仅当前文件可见,其他文件可定义同名实体,互不影响 |
| 变量修饰 | 1. extern int a;:仅声明,不分配内存;2. extern int a=10;:实际是定义,分配内存并初始化 | 1. 静态局部变量:延长生命周期至程序结束;2. 静态全局变量:文件内私有,默认初始化为0 |
| 函数修饰 | extern void func();:声明函数在其他文件定义(函数默认带extern,可省略) | static void func();:函数文件内私有,其他文件无法调用 |
| 类中使用 | 无直接作用(类成员按访问权限控制) | 修饰类静态成员:所有对象共享,无this指针,类外初始化 |
| 跨文件示例 | // file1.cpp(定义)int g_val = 100;void show() { cout << g_val; }// file2.cpp(使用)extern int g_val;extern void show();show(); → 输出100 | // file1.cppstatic int g_val = 100;static void show() { cout << g_val; }// file2.cppextern int g_val; → 编译错误(找不到定义) |
关键注意:全局变量/函数默认具有extern属性,若想限制为文件私有,需显式加static;extern仅作声明(除非初始化),不分配内存,避免重复定义。
六、函数指针与指针函数
函数指针和指针函数是C++中最易混淆的两个概念,二者语法仅差一对括号,但本质完全不同:函数指针是“指针”,指向函数;指针函数是“函数”,返回值为指针,是C++进阶开发的基础。
1. 函数指针:指向函数的指针变量
核心概念
函数在内存中拥有唯一的入口地址,函数指针是一种特殊的指针变量,其值为函数的内存入口地址,通过函数指针可以间接调用函数,实现“函数的参数化传递”,是回调函数、策略模式的核心基础。
函数指针的类型由函数的返回值和参数列表决定(与函数名无关),函数名本身就是函数的入口地址(如func等价于&func)。
定义语法
函数指针的定义需严格匹配目标函数的返回值类型和参数列表(类型+个数+顺序),括号不可省略(优先级问题),有两种定义方式:
- 直接定义:返回值类型 (*函数指针名)(参数类型1, 参数类型2, …); 示例:int (*pFunc)(int, int); // 指向“接收两个int、返回int”的函数
- 类型别名定义(推荐,简化复杂类型):typedef int (*FuncType)(int, int); // typedef方式
using FuncType = int (*)(int, int); // C++11 using方式(更直观)
FuncType pFunc; // 定义函数指针变量
使用步骤与示例
步骤:定义匹配的函数 → 将函数地址赋值给函数指针 → 通过函数指针间接调用函数(*可省略)。
#include <iostream>
using namespace std;
// 1. 定义匹配的函数
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a – b; }
int main() {
// 2. 定义函数指针并赋值(&可省略)
int (*pFunc)(int, int) = add;
// 3. 间接调用函数(两种方式等价,*可省略)
cout << (*pFunc)(2, 3) << endl; // 标准写法,输出5
cout << pFunc(5, 2) << endl; // 简化写法,输出3
// 重新指向其他匹配函数
pFunc = sub;
cout << pFunc(5, 2) << endl; // 输出3
return 0;
}
核心使用场景
- 回调函数:操作完成后自动调用预先注册的函数,如C语言qsort的比较函数、异步操作的完成回调、框架钩子函数;
- 策略模式:将不同业务逻辑封装为函数,通过函数指针动态选择执行策略,替代大量if-else/switch,提升代码灵活性;
- 类的成员函数指针:类的非静态成员函数含隐式this指针,需指定类名定义:int (Math::*pMemFunc)(int, int) = &Math::add;(&不可省略);
- 函数表/插件架构:通过函数指针数组存储多个同类型函数,实现动态函数调用,适用于插件、驱动开发。
回调函数示例:
#include <iostream>
#include <cstdlib> // qsort头文件
using namespace std;
// 回调函数1:int升序比较
int compare_asc(const void* a, const void* b) {
return *(const int*)a – *(const int*)b;
}
// 回调函数2:int降序比较
int compare_desc(const void* a, const void* b) {
return *(const int*)b – *(const int*)a;
}
int main() {
int arr[] = {3,1,4,2};
int n = sizeof(arr)/sizeof(arr[0]);
// qsort第四个参数是函数指针:动态传递比较策略
qsort(arr, n, sizeof(int), compare_asc); // 升序排序
for(int x : arr) cout << x << " "; // 1 2 3 4
qsort(arr, n, sizeof(int), compare_desc); // 降序排序
for(int x : arr) cout << x << " "; // 4 3 2 1
return 0;
}
2. 指针函数:返回指针类型的函数
核心概念
指针函数是一种普通函数,其核心特征是返回值为指针类型,语法上无特殊修饰,仅需将返回值类型声明为指针即可,是动态内存分配、返回数组/对象地址的常用方式。
定义语法
返回值类型* 函数名(参数类型1, 参数类型2, …); 示例:int* createArr(int n); // 返回int类型指针的函数,接收一个int参数
使用示例
#include <iostream>
using namespace std;
// 指针函数:动态创建int数组,返回数组指针
int* createArr(int n) {
if (n <= 0) return nullptr;
int* arr = new int[n]; // 动态分配堆内存
for(int i=0; i<n; i++) {
arr[i] = i * 2; // 初始化数组
}
return arr; // 返回堆内存指针
}
int main() {
int* p = createArr(5);
if (p != nullptr) {
for(int i=0; i<5; i++) {
cout << p[i] << " "; // 0 2 4 6 8
}
delete[] p; // 手动释放堆内存,避免泄漏
p = nullptr;
}
return 0;
}
核心注意事项
- 指针函数不能返回栈内存指针(如int* func() { int a; return &a; }),栈内存随函数调用结束销毁,返回后会成为悬空指针;
- 若返回堆内存指针,调用者需手动释放内存(delete/delete[]),避免内存泄漏;
- 指针函数的返回值可做链式访问,如node* getNext(node* p) { return p->next; },可连续调用getNext(getNext(p))。
3. 函数指针与指针函数核心对比
| 本质 | 特殊的指针变量,指向函数的入口地址 | 普通的函数,返回值为指针类型 |
| 核心语法 | 括号不可省略:int (*p)(int, int) | 无额外括号:int* f(int, int) |
| 优先级关键 | (*p)提升*优先级,先表示指针,再关联函数 | 函数调用符()优先级高于*,先表示函数,再关联返回值指针 |
| 内存存储 | 存储在栈区/数据段(指针变量),值为函数代码段地址 | 本身是函数代码段,返回值是指向栈/堆/数据段的指针 |
| 核心用途 | 回调函数、策略模式、动态函数调用、插件架构 | 动态内存分配、返回数组/对象地址、链式访问 |
| 易混点 | 省略括号则变为指针函数:int *p(int, int) | 加括号则语法错误:int* (f)(int, int)(函数名不能被括号包裹) |
记忆技巧:看括号和*的结合关系——(*名)是函数指针(名是指针),类型* 名()是指针函数(名是函数)。
七、结构体与类:C++面向对象的基础载体
struct和class是C++实现面向对象编程的核心载体,二者功能几乎完全一致,仅默认访问权限和默认继承方式不同,适用于不同的编程场景。
1. 核心区别
| 默认访问权限 | public(公有):成员可直接被外部访问 | private(私有):成员不可被外部访问,需通过公有接口访问 |
| 默认继承方式 | 公有继承(public):基类的公有/保护成员在派生类中保持原有权限 | 私有继承(private):基类的公有/保护成员在派生类中变为私有 |
| 核心设计意图 | 侧重组织数据,实现数据的聚合,偏向面向过程编程 | 侧重封装数据与操作,实现属性和方法的绑定,偏向面向对象编程 |
| 适用场景 | 存储简单的纯数据结构(如坐标、学生信息、配置参数) | 实现复杂的业务逻辑,封装属性和方法,支持继承、多态等面向对象特性 |
2. 实用示例
#include <iostream>
#include <string>
using namespace std;
// struct:纯数据结构,默认public,仅存储数据
struct Student {
string name; // 公有成员,可直接访问
int age;
float score;
};
// class:封装数据与操作,默认private,通过公有接口访问
class Calculator {
private: // 默认private,外部不可访问
int result; // 私有属性,仅类内可修改
public:
// 构造函数:初始化属性
Calculator() : result(0) {}
// 公有方法:提供外部访问接口
void add(int num) { result += num; }
void sub(int num) { result -= num; }
int getResult() const { return result; } // const成员函数,不修改属性
};
int main() {
// struct使用:直接访问成员
Student s = {"张三", 18, 95.5};
cout << "姓名:" << s.name << " 年龄:" << s.age << endl;
// class使用:通过公有接口访问
Calculator cal;
cal.add(10);
cal.sub(3);
cout << "计算结果:" << cal.getResult() << endl; // 7
return 0;
}
注意:struct在C++中并非单纯的C语言结构体,也支持成员函数、构造函数、继承、多态等面向对象特性,仅默认规则与class不同;开发中可根据设计意图选择,无需严格区分。
八、总结
C++基础知识点核心围绕内存管理、类型安全、作用域控制、代码解耦四大核心思想展开,核心要点可归纳为:
网硕互联帮助中心





评论前必须登录!
注册