内部对象
约 1312 个字 287 行代码 预计阅读时间 14 分钟
对象内部机制
本章探讨C++对象的内部实现机制,包括访问控制、对象在不同位置的表现、静态成员、引用、常量以及动态内存分配。
访问控制
-
访问修饰符
- 所有成员声明对所有人开放
- 任何代码都可以访问public成员
- 除了类内部成员函数,其他地方不能访问
- 实现信息隐藏,保护数据安全
- 本类和派生类可见
- 在继承中使用(后续章节详述)
-
友元
- 授权非成员函数访问私有成员
- 授权整个类访问私有成员
struct vs class
C++中,struct和class的唯一区别是默认访问权限不同:
- struct
默认为public
(兼容C语言)
- class
默认为private
(强调信息隐藏)
对象位置与生命周期
-
局部对象
- 定义在函数内部
- 作用域仅限于所在函数或代码块
- 生命周期从定义点到作用域结束
类型 作用域 生命周期 特点 字段(field) 整个类 对象的生命周期 使用this指针访问 参数(parameter) 函数内部 函数调用期间 由调用者初始化 局部变量(local variable) 定义块内 块执行期间 需手动初始化 -
全局对象
- 定义在任何函数外部
- 作用域为整个程序
- 在程序启动前构造,程序结束时销毁
- 同一文件中的全局对象按声明顺序构造
- 不同文件中的全局对象构造顺序不确定
- 析构顺序与构造顺序相反
静态成员
- 静态存储:在固定地址上分配,程序整个生命周期存在
- 名称可见性限制:内部链接
C++中static
的使用场景:
使用位置 | 含义 |
---|---|
自由函数 | 内部链接(不推荐) |
全局变量 | 内部链接(不推荐) |
局部变量 | 持久存储 |
类成员变量 | 由所有实例共享 |
类成员函数 | 由所有实例共享,只能访问静态成员 |
在函数内部声明的静态变量,其值在程序的整个生命周期内保持:
特点: - 初始化只发生一次 - 值在函数调用间保持 - 作用域仍限于函数内部静态成员变量:
class Counter {
private:
static int count; // 声明静态成员
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { return count; }
};
// 在类外定义并初始化静态成员(必需)
int Counter::count = 0; // 不再使用static关键字
静态成员函数:
class X {
private:
int i;
static int count;
public:
static void showCount() {
cout << count << endl; // 正确:访问静态成员
// cout << i << endl; // 错误:不能访问非静态成员
}
};
访问静态成员的方式:
引用
-
引用基础
引用是C++中操作对象的新方式,本质上是对象的别名:
- 引用必须在定义时初始化
- 初始化建立绑定,之后不能更改
- 引用的目标必须有位置(左值)
特性 引用 指针 可为空 否 是 依赖现有变量 是 否 可更改指向 否 是 使用方式 直接使用 需解引用 初始化 必须初始化 可以不初始化 -
右值引用
C++11引入的特性,可以绑定到临时对象(右值):
可以基于参数是左值还是右值进行重载:
常量
-
常量基础
常量是不可修改的变量:
- 常量遵循作用域规则
- C++中的const默认为内部链接
- 编译器尽量避免为const分配存储空间
- 使用
extern
可强制分配存储空间
-
指针与常量
两种不同的概念:
解读复杂声明的技巧:
-
常量与类
不能修改类的状态:
只能调用常量成员函数:
动态内存分配
动态分配内存是C++的重要特性:
使用new/delete的注意事项:
- 不要用delete释放非new分配的内存
- 不要重复释放同一块内存
- 用new[ ]分配的数组必须用delete[ ]释放
- 用new分配的单个对象必须用delete释放
- 对空指针使用delete是安全的(无操作)
智能指针
C++11引入了智能指针,可以自动管理内存,避免内存泄漏: