跳到主要内容

C++ 嵌套类

在C++的面向对象编程中,嵌套类是一个强大而灵活的特性,它允许我们在一个类的内部定义另一个类。嵌套类(也称为内部类)可以帮助我们组织代码结构,增强封装性,并且创建更紧密关联的类层次结构。

什么是嵌套类?

嵌套类是指在另一个类的定义内部声明的类。外部类包含内部类的定义,但它们仍是独立的数据类型。

备注

嵌套类与外部类有特殊的访问关系,但它们的实例是完全独立的对象。

基本语法

嵌套类的基本语法如下:

cpp
class OuterClass {
public:
// 外部类的成员和方法

class NestedClass {
public:
// 嵌套类的成员和方法
};

private:
// 外部类的私有成员
};

嵌套类的特性与访问规则

嵌套类具有以下重要特性:

  1. 作用域:嵌套类的名称在外部类的作用域内可见。
  2. 访问控制:嵌套类可以访问外部类的类型名称、静态成员和枚举,但不能直接访问外部类的非静态成员。
  3. 可见性:嵌套类受外部类的访问修饰符控制,决定其对外可见性。

让我们看一个简单的例子:

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;
}

输出结果:

这是公有嵌套类
这是私有嵌套类

外部类与嵌套类的交互

虽然嵌套类不能直接访问外部类的非静态成员,但可以通过以下方式实现交互:

  1. 将外部类对象作为参数传递给嵌套类
  2. 使用友元关系
  3. 在外部类中创建和管理嵌套类实例
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中的内部类对象包含一个隐式引用,可以直接访问外部类的所有成员。

嵌套类的优缺点

优点:

  1. 提高封装性:将仅在外部类中使用的类型隐藏起来
  2. 逻辑组织:将相关类型放在一起,提高代码可读性
  3. 访问控制:通过访问修饰符控制嵌套类的可见性
  4. 命名空间管理:避免全局命名空间污染

缺点:

  1. 复杂性增加:嵌套结构可能使代码难以理解
  2. 外部访问限制:如果嵌套类定义为私有,外部代码无法直接使用
  3. 编译依赖:嵌套类的修改可能导致外部类需要重新编译

嵌套类使用建议

  1. 当一个类仅对另一个类有意义时,考虑使用嵌套类
  2. 对于实现细节使用私有嵌套类,对于可重用组件使用公有嵌套类
  3. 使用嵌套类实现辅助结构、迭代器、状态等设计模式
  4. 避免过深的嵌套,通常不建议超过一层嵌套

总结

嵌套类是C++面向对象编程中的一项强大特性,它提供了更好的封装性和代码组织方式。通过将相关类型定义在一个类的内部,我们可以创建更具内聚性的代码结构,并控制类型的可见性。嵌套类在实现数据结构、设计模式以及特定问题解决方案中有广泛应用。

掌握嵌套类的使用,将帮助您创建更加模块化、可维护的C++代码。

练习

  1. 创建一个 School 类,其中包含一个 Student 嵌套类。实现添加学生、显示所有学生信息的功能。
  2. 实现一个二叉树类 BinaryTree,使用嵌套类 Node 表示树节点。
  3. 设计一个自定义容器类,并为其实现迭代器(使用嵌套类)。
  4. 尝试使用嵌套类实现观察者设计模式。

进一步学习资源

  • C++标准库中嵌套类的使用(如 std::map 中的嵌套类 value_compare
  • 设计模式中的嵌套类应用
  • C++高级编程技巧与最佳实践