C++ 现代C++编程艺术6-类的内部类
文章目录
C++ 内部类(嵌套类)是定义在另一个类内部的类,主要用于封装关联逻辑、隐藏实现细节或优化代码组织。
一、内部类基础概念
内部类(嵌套类) 是定义在另一个类内部的类,主要用于:
- 封装关联逻辑:将紧密相关的类组织在一起
- 隐藏实现细节:限制内部类的可见性
- 优化代码组织:提高代码的内聚性和可读性
- 减少命名冲突:通过类作用域隔离标识符
class Outer {
public:
class Inner { // 内部类声明
// 成员定义
};
};
二、核心应用场景与代码示例
1. 隐藏派生类(实现工厂模式)
// 基类接口
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() = default;
};
class ShapeFactory {
public:
static Shape* createCircle() {
return new InnerCircle(); // 返回内部类实例
}
private:
// 私有内部类实现
class InnerCircle : public Shape {
public:
void draw() override {
std::cout << "Drawing Circle" << std::endl;
}
};
};
int main() {
// 使用示例
Shape* circle = ShapeFactory::createCircle();
circle->draw(); // 输出: Drawing Circle
delete circle;
return 0;
}
2. 模板化内部类(泛型编程)
#include <iostream>
#include <vector>
#include <stdexcept> // 包含标准异常头文件
template <typename T>
class Matrix {
public:
// 默认构造函数创建空矩阵
Matrix() = default;
// 带参数的构造函数
Matrix(size_t rows, size_t cols) : data(rows, std::vector<T>(cols)) {}
// 模板内部类:行迭代器
class RowIterator {
private:
T* currentRow;
size_t rowSize = 0; // 存储行大小信息
public:
explicit RowIterator(T* row, size_t size)
: currentRow(row), rowSize(size) {}
// 下标访问运算符
T& operator[](size_t col) {
if (col >= rowSize) {
throw std::out_of_range("Column index out of range");
}
return currentRow[col];
}
// 只读版本的下标访问
const T& operator[](size_t col) const {
if (col >= rowSize) {
throw std::out_of_range("Column index out of range");
}
return currentRow[col];
}
// 获取行首指针
T* begin() { return currentRow; }
// 获取行尾指针
T* end() { return currentRow + rowSize; }
// 获取行大小
size_t size() const { return rowSize; }
};
// 矩阵行访问运算符
RowIterator operator[](size_t row) {
if (row >= data.size()) {
throw std::out_of_range("Row index out of range");
}
// 传递行指针和行大小
return RowIterator(data[row].data(), data[row].size());
}
// 只读版本的行访问
const RowIterator operator[](size_t row) const {
if (row >= data.size()) {
throw std::out_of_range("Row index out of range");
}
return RowIterator(data[row].data(), data[row].size());
}
// 安全元素访问接口
T& at(size_t row, size_t col) {
if (row >= data.size()) {
throw std::out_of_range("Row index out of range");
}
if (col >= data[row].size()) {
throw std::out_of_range("Column index out of range");
}
return data[row][col];
}
// 只读安全访问
const T& at(size_t row, size_t col) const {
if (row >= data.size()) {
throw std::out_of_range("Row index out of range");
}
if (col >= data[row].size()) {
throw std::out_of_range("Column index out of range");
}
return data[row][col];
}
// 获取行数
size_t rows() const { return data.size(); }
// 获取列数(假设所有行大小相同)
size_t cols() const {
if (data.empty()) return 0;
return data[0].size();
}
// 改变矩阵大小
void resize(size_t rows, size_t cols) {
data.resize(rows);
for (auto& row : data) {
row.resize(cols);
}
}
private:
std::vector<std::vector<T>> data;
};
int main() {
try {
// 创建3x4矩阵
Matrix<int> mat1(3, 4);
// 初始化矩阵值
for (size_t i = 0; i < mat1.rows(); ++i) {
for (size_t j = 0; j < mat1.cols(); ++j) {
mat1[i][j] = static_cast<int>(i * mat1.cols() + j);
}
}
// 访问元素
auto row = mat1[2]; // 获取第三行
int value = row[3]; // 访问第四列元素
std::cout << "Value at [2][3]: " << value << std::endl; // 应该输出11
// 测试边界检查
try {
int invalid = mat1[5][2]; // 越界访问
} catch (const std::out_of_range& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}
// 使用默认构造函数创建矩阵
Matrix<float> mat2;
mat2.resize(2, 3); // 调整大小
// 填充数据
for (size_t i = 0; i < mat2.rows(); ++i) {
for (size_t j = 0; j < mat2.cols(); ++j) {
mat2[i][j] = static_cast<float>(i * 10 + 0.123);
}
}
// 访问元素
std::cout << "Value at [1][2]: " << mat2[1][2] << std::endl; // 应该输出 10.123
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
3. 模板特化与友元关系
template<typename T>
class Container {
T data;
// 每个模板实例独立声明友元
friend class Iterator;
public:
class Iterator {
public:
void reset(Container& c) {
c.data = T{}; // 访问外部类私有成员
}
const T& get(const Container& c) const {
return c.data; // 只读访问
}
};
};
// 使用示例
Container<int> intContainer;
Container<int>::Iterator intIter;
intIter.reset(intContainer);
Container<std::string> strContainer;
Container<std::string>::Iterator strIter;
strIter.reset(strContainer);
三、高级应用技巧
-
元编程支持
class TypeTraits { public: // 类型特征提取内部类 template<typename T> class TypeInfo { public: static constexpr bool is_integral = std::is_integral_v<T>; static constexpr bool is_pointer = std::is_pointer_v<T>; static std::string name() { if constexpr (is_integral) return "Integral"; else if constexpr (is_pointer) return "Pointer"; else return "Unknown"; } }; }; // 使用示例 std::cout << TypeTraits::TypeInfo<int>::name(); // 输出: Integral std::cout << TypeTraits::TypeInfo<int*>::name(); // 输出: Pointer
-
访问控制模式
class SecureSystem { private: int secretKey = 0xDEADBEEF; // 特权访问内部类 class PrivilegedAccess { public: static int getKey(SecureSystem& sys) { return sys.secretKey; // 直接访问私有成员 } }; public: // 公开API委托特权访问 int getPublicKey() { return PrivilegedAccess::getKey(*this); } }; // 使用示例 SecureSystem system; int key = system.getPublicKey(); // 通过受控接口访问
四、关键注意事项
-
访问权限规则
访问方向 权限要求 示例 内部类→外部类 需通过实例访问 outerObj.member
外部类→内部类 需声明为友元 friend class Outer;
静态成员访问 直接访问 Outer::staticMember
-
生命周期管理
class ResourceHolder { public: class ResourceHandle { public: ResourceHandle(ResourceHolder& holder) : parent(holder) {} void useResource() { if (!parent.resourceActive) { throw std::runtime_error("Resource unavailable"); } // 使用资源... } private: ResourceHolder& parent; // 持有父类引用 }; ResourceHandle getHandle() { return ResourceHandle(*this); } ~ResourceHolder() { resourceActive = false; // 使所有handle失效 } private: bool resourceActive = true; };
-
设计最佳推荐
- 封装边界:使用
private
内部类彻底隐藏实现 - 接口隔离:通过公共内部类定义子模块接口
- 模板特化:为不同模板实例提供定制化内部类
- 循环引用:避免内部类与外部类相互依赖
- 编译器影响:注意嵌套深度对编译性能的影响
- 封装边界:使用
五、应用场景总结
场景 | 技术方案 | 优势 |
---|---|---|
实现隐藏 | 私有内部类 + 工厂方法 | 完全封装实现细节 |
泛型迭代器 | 模板内部类 + 运算符重载 | 类型安全遍历 |
有限继承 | 保护内部类 + 静态工厂 | 控制派生范围 |
特权访问 | 友元内部类 + 代理接口 | 细粒度权限控制 |
编译期计算 | 静态成员内部类 + constexpr | 零开销抽象 |
内部类应保持职责单一,深度嵌套超过两层时,应考虑重构为独立类。
内部类作为C++强大的封装机制,合理使用可显著提升代码的模块化和类型安全性。在框架设计、模板元编程和接口隔离等场景中,它能提供优雅的解决方案,但需警惕过度使用导致的编译依赖和代码可读性问题。