Menu
CoddyTech

图形容器

本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 48 课,共 61 课。

challenge icon

挑战

简单

让 Shape Drawer 项目迎来盛大的收尾吧!你将创建一个形状容器,用来存放由圆形和矩形组成的混合集合,然后遍历它们来计算总面积,展现多态的真正威力。

在你目前完成的所有内容基础上,完整的项目将包括:

  • shape.h 和 shape.c:基础 Shape 接口和 process_shape 函数。
  • circle.h 和 circle.c:Circle 的实现,包括构造函数和面积计算。
  • rectangle.h 和 rectangle.c:Rectangle 的实现,包括构造函数和面积计算。
  • main.c:这里就是见证奇迹的地方。你将创建一个由 Shape* 指针组成的数组,它可以存放任意形状类型。用各种 Circle 和 Rectangle 填充数组,然后遍历数组,计算并显示所有形状的总面积。

你的程序将接收以下输入:

  1. 要创建的形状数量
  2. 每个形状的信息:类型标识符(c 表示圆形,r 表示矩形),后面跟着它的尺寸

对于容器中的每个形状,通过 Shape* 指针自行调用 draw 和 area(shapes[i]->draw(shapes[i])、shapes[i]->area(shapes[i])),并将面积累加到总数中。这里不要使用 shape.c 中的 process_shape:它会为每个形状额外输出一行 Area:,而预期输出中不包含这一行。处理完所有形状后,按照 Total Area: X.XX 的格式,以 2 位小数输出总面积。

输入示例:3,然后是 c 5.0、r 4.0 3.0、c 2.0:

Drawing Circle with radius: 5.00
Drawing Rectangle with width: 4.00 and height: 3.00
Drawing Circle with radius: 2.00
Total Area: 103.11

输入示例:2,然后是 r 6.0 4.0、r 3.0 2.0:

Drawing Rectangle with width: 6.00 and height: 4.00
Drawing Rectangle with width: 3.00 and height: 2.00
Total Area: 30.00

关键在于,数组存储的是 Shape* 指针。它不关心每个元素实际上是 Circle 还是 Rectangle。遍历数组并通过每个指针调用 draw 和 area 时,会根据各个形状的构造方式自动执行正确的实现。这就是多态的作用:一个循环、一个接口,多种行为。

记住,你需要将具体形状中嵌入的 Shape 成员的指针存入数组。计算圆形面积时,π 使用 3.14159。

重要提示:读取形状类型字符:使用 scanf("%d", &n) 读取形状数量后,每次读取类型字符时都必须跳过输入缓冲区中剩余的换行符。请在格式字符串开头加一个空格来实现:

scanf(" %c", &type);  // note the space before %c

如果不加这个前导空格,scanf 会读取上一次输入留下的换行符,而不是预期的 c 或 r,导致形状类型检查悄无声息地失败,并且不产生任何输出。

亲手试试

#include <stdio.h>
#include <stdlib.h>
#include "shape.h"
#include "circle.h"
#include "rectangle.h"

int main() {
    // TODO: 读取形状的数量
    // TODO: 为圆形、矩形和 Shape* 指针分配数组
    // TODO: 循环遍历每个形状,读取其类型和尺寸,
    //       创建形状,并将指向其基类的指针存入 shapes 数组
    // TODO: 循环遍历 shapes 数组,调用 shapes[i]->draw(...) 和
    //       直接调用 shapes[i]->area(...),并累加总面积
    //       (不要调用 process_shape:它会额外输出一行 Area)
    // TODO: 按以下格式输出总面积:Total Area: X.XX
    // TODO: 释放已分配的内存
    return 0;
}

面向对象编程中的所有课

自己练习: C 在线编译器