C++ 嵌套类
在C++的面向对象编程中,嵌套类是一个强大而灵活的特性,它允许我们在一个类的内部定义另一个类。嵌套类(也称为内部类)可以帮助我们组织代码结构,增强封装性,并且创建更紧密关联的类层次结构。
什么是嵌套类?
嵌套类是指在另一个类的定义内部声明的类。外部类包含内部类的定义,但它们仍是独立的数据类型。
备注
嵌套类与外部类有特殊的访问关系,但它们的实例是完全独立的对象。
基本语法
嵌套类的基本语法如下:
cpp
class OuterClass {
public:
// 外部类的成员和方法
class NestedClass {
public:
// 嵌套类的成员和方法
};
private:
// 外部类的私有成员
};
嵌套类的特性与访问规则
嵌套类具有以下重要特性:
- 作用域:嵌套类的名称在外部类的作用域内可见。
- 访问控制:嵌套类可以访问外部类的类型名称、静态成员和枚举,但不能直接访问外部类的非静态成员。
- 可见性:嵌套类受外部类的访问修饰符控制,决定其对外可见性。
让我们看一个简单的例子:
cpp
#include <iostream>
class OuterClass {
public:
static int outerStaticValue;
int outerValue;
class NestedClass {
public:
void display() {
// 可以访问外部类的静态成员
std::cout << "外部类的静态值: " << outerStaticValue << std::endl;
// 但不能直接访问非静态成员
// std::cout << outerValue; // 错误!
}
};
void createNestedObject() {
NestedClass nested;
nested.display();
}
};
// 初始化静态成员
int OuterClass::outerStaticValue = 100;
int main() {
// 创建嵌套类的对象
OuterClass::NestedClass nestedObj;
nestedObj.display();
return 0;
}
输出结果:
外部类的静态值: 100
嵌套类的访问修饰符
嵌套类的可见性受其在外部类中声明所用的访问修饰符控制:
cpp
class OuterClass {
public:
class PublicNested {
// 从外部可访问
};
protected:
class ProtectedNested {
// 仅子类可访问
};
private:
class PrivateNested {
// 仅OuterClass可访问
};
};
示例代码展示不同访问级别:
cpp
#include <iostream>
class OuterClass {
public:
class PublicNested {
public:
void display() {
std::cout << "这是公有嵌套类" << std::endl;
}
};
private:
class PrivateNested {
public:
void display() {
std::cout << "这是私有嵌套类" << std::endl;
}
};
public:
// 通过外部类访问私有嵌套类
void accessPrivateNested() {
PrivateNested pn;
pn.display();
}
};
int main() {
// 可以直接访问公有嵌套类
OuterClass::PublicNested publicNested;
publicNested.display();
// 不能直接访问私有嵌套类
// OuterClass::PrivateNested privateNested; // 错误!
// 但可以通过外部类提供的方法间接访问
OuterClass outer;
outer.accessPrivateNested();
return 0;
}
输出结果:
这是公有嵌套类
这是私有嵌套类
外部类与嵌套类的交互
虽然嵌套类不能直接访问外部类的非静态成员,但可以通过以下方式实现交互:
- 将外部类对象作为参数传递给嵌套类
- 使用友元关系
- 在外部类中创建和管理嵌套类实例
cpp
#include <iostream>
#include <string>
class Person {
private:
std::string name;
int age;
public:
Person(const std::string& n, int a) : name(n), age(a) {}
class Address {
private:
std::string street;
std::string city;
public:
Address(const std::string& s, const std::string& c) : street(s), city(c) {}
void display(const Person& p) {
// 通过引用访问外部类实例
std::cout << p.name << " 住在 " << city << "市 " << street << std::endl;
}
};
// 外部类访问嵌套类
void showAddress(const Address& addr) {
std::cout << name << " 的地址信息:" << std::endl;
addr.display(*this);
}
};
int main() {
Person person("张三", 30);
Person::Address address("和平路123号", "北京");
person.showAddress(address);
return 0;
}
输出结果:
张三 的地址信息:
张三 住在 北京市 和平路123号
嵌套类的实际应用场景
1. 辅助数据结构
当某个类需要特定的辅助数据结构,而这个结构在类外部没有独立意义时,嵌套类是理想选择。
cpp
class LinkedList {
private:
// 节点作为嵌套类
class Node {
public:
int data;
Node* next;
Node(int val) : data(val), next(nullptr) {}
};
Node* head;
public:
LinkedList() : head(nullptr) {}
void append(int value) {
Node* newNode = new Node(value);
if (!head) {
head = newNode;
return;
}
Node* current = head;
while (current->next) {
current = current->next;
}
current->next = newNode;
}
void display() {
Node* current = head;
while (current) {
std::cout << current->data << " ";
current = current->next;
}
std::cout << std::endl;
}
~LinkedList() {
Node* current = head;
while (current) {
Node* next = current->next;
delete current;
current = next;
}
}
};
2. 迭代器模式
嵌套类常用于实现迭代器模式:
cpp
#include <iostream>
#include <vector>
class Collection {
private:
std::vector<int> data;
public:
// 添加元素
void add(int value) {
data.push_back(value);
}
// 迭代器嵌套类
class Iterator {
private:
const Collection& collection;
size_t index;
public:
Iterator(const Collection& coll) : collection(coll), index(0) {}
bool hasNext() const {
return index < collection.data.size();
}
int next() {
return collection.data[index++];
}
};
// 获取迭代器
Iterator getIterator() const {
return Iterator(*this);
}
};
int main() {
Collection numbers;
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(40);
Collection::Iterator it = numbers.getIterator();
while (it.hasNext()) {
std::cout << it.next() << " ";
}
std::cout << std::endl;
return 0;
}
输出结果:
10 20 30 40
3. 状态模式实现
嵌套类也适合用于状态模式:
cpp
#include <iostream>
#include <string>
class Document {
public:
// 文档状态基类 - 嵌套类
class State {
protected:
Document* document;
public:
State(Document* doc) : document(doc) {}
virtual ~State() {}
virtual void view() = 0;
virtual void edit() = 0;
virtual std::string getName() = 0;
};
private:
State* currentState;
std::string content;
// 具体状态 - 草稿状态
class DraftState : public State {
public:
DraftState(Document* doc) : State(doc) {}
void view() override {
std::cout << "查看草稿内容" << std::endl;
}
void edit() override {
std::cout << "编辑草稿内容" << std::endl;
}
std::string getName() override {
return "草稿状态";
}
};
// 具体状态 - 审核状态
class ModeratingState : public State {
public:
ModeratingState(Document* doc) : State(doc) {}
void view() override {
std::cout << "查看审核中的内容" << std::endl;
}
void edit() override {
std::cout << "审核中的文档不可编辑" << std::endl;
}
std::string getName() override {
return "审核状态";
}
};
// 具体状态 - 已发布状态
class PublishedState : public State {
public:
PublishedState(Document* doc) : State(doc) {}
void view() override {
std::cout << "查看已发布的内容" << std::endl;
}
void edit() override {
std::cout << "已发布的文档不可直接编辑" << std::endl;
}
std::string getName() override {
return "已发布状态";
}
};
public:
Document() : content("") {
currentState = new DraftState(this);
}
~Document() {
delete currentState;
}
void setState(State* state) {
delete currentState;
currentState = state;
}
void makeDraft() {
setState(new DraftState(this));
}
void sendForModeration() {
setState(new ModeratingState(this));
}
void publish() {
setState(new PublishedState(this));
}
void view() {
currentState->view();
}
void edit() {
currentState->edit();
}
std::string getStateName() {
return currentState->getName();
}
};
int main() {
Document doc;
std::cout << "当前状态: " << doc.getStateName() << std::endl;
doc.edit(); // 可以编辑
doc.sendForModeration();
std::cout << "当前状态: " << doc.getStateName() << std::endl;
doc.edit(); // 不可编辑
doc.publish();
std::cout << "当前状态: " << doc.getStateName() << std::endl;
doc.view();
return 0;
}
输出结果:
当前状态: 草稿状态
编辑草稿内容
当前状态: 审核状态
审核中的文档不可编辑
当前状态: 已发布状态
查看已发布的内容
嵌套类与内部类的区别
嵌套类是C++中的概念,而内部类通常指Java中的概念。它们有一个重要区别:
警告
C++的嵌套类对象不含有指向外部类对象的隐式指针,它无法直接访问外部类的非静态成员。 而Java中的内部类对象包含一个隐式引用,可以直接访问外部类的所有成员。
嵌套类的优缺点
优点:
- 提高封装性:将仅在外部类中使用的类型隐藏起来
- 逻辑组织:将相关类型放在一起,提高代码可读性
- 访问控制:通过访问修饰符控制嵌套类的可见性
- 命名空间管理:避免全局命名空间污染
缺点:
- 复杂性增加:嵌套结构可能使代码难以理解
- 外部访问限制:如果嵌套类定义为私有,外部代码无法直接使用
- 编译依赖:嵌套类的修改可能导致外部类需要重新编译
嵌套类使用建议
- 当一个类仅对另一个类有意义时,考虑使用嵌套类
- 对于实现细节使用私有嵌套类,对于可重用组件使用公有嵌套类
- 使用嵌套类实现辅助结构、迭代器、状态等设计模式
- 避免过深的嵌套,通常不建议超过一层嵌套
总结
嵌套类是C++面向对象编程中的一项强大特性,它提供了更好的封装性和代码组织方式。通过将相关类型定义在一个类的内部,我们可以创建更具内聚性的代码结构,并控制类型的可见性。嵌套类在实现数据结构、设计模式以及特定问题解决方案中有广泛应用。
掌握嵌套类的使用,将帮助您创建更加模块化、可维护的C++代码。
练习
- 创建一个
School
类,其中包含一个Student
嵌套类。实现添加学生、显示所有学生信息的功能。 - 实现一个二叉树类
BinaryTree
,使用嵌套类Node
表示树节点。 - 设计一个自定义容器类,并为其实现迭代器(使用嵌套类)。
- 尝试使用嵌套类实现观察者设计模式。
进一步学习资源
- C++标准库中嵌套类的使用(如
std::map
中的嵌套类value_compare
) - 设计模式中的嵌套类应用
- C++高级编程技巧与最佳实践