题目
编写程序,设计具有纯虚函数(virtual void func() = 0;)的抽象接口类(Interface)ILogger。展示抽象类无法被实例化(直接定义对象将引发编译器阻止)的契约强制性;设计具体的派生实现类 ConsoleLogger 与 FileLogger 必须完整实现所有的纯虚函数,否则派生类将继续保持为抽象类。通过统一接口驱动不同的日志持久化插件。
输入格式:无需外部输入。
输出格式:输出基于纯虚接口的抽象依赖注入与不同插件实现输出。
数据范围与约定:接口设计、面向接口编程契约与纯虚函数语法。
思路与算法
1. 纯虚函数的声明与意义
在虚函数声明末尾加上 = 0 即构成纯虚函数。它只定义方法签名规范(接口协议),不要求提供默认实现(但 C++ 允许为纯虚函数提供外部定义体)。
2. 抽象类的不可实例化约束
包含至少一个纯虚函数的类就是抽象类(Abstract Class)。尝试编写 ILogger logger; 会被编译器严厉报错。它存在的唯一目的就是作为基类被派生实现。
3. 依赖倒置原则(DIP)
高层业务模块只依赖抽象接口 ILogger&,而不直接依赖具体的 ConsoleLogger,实现了软件工程中高度解耦的插件式架构。
完整程序
#include <iostream>
#include <string>
#include <memory>
#include <vector>
// 纯虚抽象接口类(契约)
class ILogger {
public:
virtual ~ILogger() = default; // 虚析构
// 纯虚函数:派生类必须无条件提供实现
virtual void log(const std::string& msg) = 0;
virtual std::string getChannel() const = 0;
};
// 具体实现 1:控制台日志器
class ConsoleLogger : public ILogger {
public:
void log(const std::string& msg) override {
std::cout << "[控制台标准流] " << msg << "\n";
}
std::string getChannel() const override {
return "STDOUT_CONSOLE";
}
};
// 具体实现 2:文件模拟日志器
class MockFileLogger : public ILogger {
public:
void log(const std::string& msg) override {
std::cout << "[模拟持久化文件写入] >>> " << msg << "\n";
}
std::string getChannel() const override {
return "FILE_APP_LOG";
}
};
// 面向接口的高层服务,与底层日志具体实现完全解耦
void businessService(ILogger& logger, const std::string& task) {
std::cout << ">>> 触发服务业务: \"" << task << "\" (通道: " << logger.getChannel() << ")\n";
logger.log("业务 [" + task + "] 执行成功,状态码 200 OK");
}
int main() {
ConsoleLogger console;
MockFileLogger fileLog;
std::cout << "--- 1. 注入控制台日志实现 ---\n";
businessService(console, "UserLogin");
std::cout << "\n--- 2. 注入文件日志实现 ---\n";
businessService(fileLog, "OrderPayment");
return 0;
}运行示例
输出:
--- 1. 注入控制台日志实现 ---
>>> 触发服务业务: "UserLogin" (通道: STDOUT_CONSOLE)
[控制台标准流] 业务 [UserLogin] 执行成功,状态码 200 OK
--- 2. 注入文件日志实现 ---
>>> 触发服务业务: "OrderPayment" (通道: FILE_APP_LOG)
[模拟持久化文件写入] >>> 业务 [OrderPayment] 执行成功,状态码 200 OK