行业知识
webserver服务器从零搭建到上线(五)|noncopyable类和Logger类
文章目录
- noncopyable类
- delete掉了拷贝构造和析构
- protected成员
- 1. 允许派生
- 2.防止直接实例化
- 主要使用场景
- Logger类
- 定义日志级别
- 输出一个日志类
- 实现对应的成员函数
- 实现宏函数来调用日志类
- 知识拓展
noncopyable类
我们首先进入/muduo/net中查看TcpServer.h、EventLoop.h等等核心代码的类,都继承子一个基类noncopyable,那么我们不得不去看一下noncopyable到底是啥了
class noncopyable{ public: noncopyable(const noncopyable&) = delete; void operator=(const noncopyable&) = delete; protected: noncopyable() = default; ~noncopyable() = default;};这个类他把它的拷贝构造函数和拷贝复制运算符都delete掉了;另外他写了一个默认default的构造函数和析构函数,相当于就是给直接套了一个空的大括号,因为这两个函数编译器本来就可以自动生成。
delete掉了拷贝构造和析构
我们在使用该基类的时候,去对TcpServer的对象进行拷贝构造和赋值的时候,由于派生类的拷贝和赋值要先去调用基类的拷贝和赋值,然后才是派生类特有部分的拷贝和赋值。
但是由于基类的拷贝和赋值都被delete掉了,所以它的好处就在于我们的其他类如果不想让他被拷贝或者复制,就不用额外写这段代码了,这是一个大型程序所必须的。
总结
- 防止派生类的拷贝构造
protected成员
1. 允许派生
protected 访问修饰符使得只有 noncopyable 类及其派生类能够访问这些构造和析构函数。这意味着不能直接在 noncopyable 类的外部创建该类的实例(即不能直接实例化 noncopyable),但您可以创建派生自 noncopyable 的类的实例。
2.防止直接实例化
如果构造函数和析构函数是 public 的,那么理论上可以直接创建和销毁 noncopyable 类的对象,这违背了类的设计初衷(作为一个基类来阻止复制)。通过将构造和析构函数设为 protected,noncopyable 类的实例化只能通过其子类进行,而 noncopyable 本身不能被直接实例化。
主要使用场景
有一个管理资源的类,且这些资源不应该被复制时(比如说,单例模式、文件处理类、数据库连接管理类),您可以让这个类继承自 noncopyable,从而禁止编译时对这些资源进行复制操作。
Logger类
日志对于一个软件来说是非常重要的,如果软件上线,用gdb调试有很多不便,所以我们应该使用日志来记录问题。
定义日志级别
定义日志级别一般都是使用枚举类。
enum LogLevel {INFO,ERROR,FATAL,DEBUG,};输出一个日志类
日志类应该输出单例模式:
class Logger: noncopyable {public://获取日志唯一的实例对象static Logger& instance();//设置日志级别void setLogLevel(int level);//写日志的接口void log(std::string msg);private:int logLevel_;Logger() { }}为什么要使用单例模式呢?
- 全局访问点:单例模式确保在整个应用程序中只有一个日志类实例,方便统一管理和访问。
- 资源共享:避免多个日志实例导致的资源浪费,特别是文件句柄和网络连接等有限资源。
- 一致性:确保日志配置和行为一致,避免不同模块使用不同的日志实例导致的日志风格不一致。
实现对应的成员函数
Logger& Logger::instance() { //获取日志唯一的实例对象static Logger logger;return logger;}void Logger::setLogLevel(int level) {// 设置日志级别logLevel_ = level;}void Logger::log(std::string msg) {//写日志的接口 【级别信息】time : xxx switch (logLevel_) { case INFO: std::cout \Logger &logger = Logger::instance(); \logger.setLogLevel(INFO); \char buf[1024] = { 0 }; \snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \logger.log(buf); \} while(0) \ Logger &logger = Logger::instance(); \ logger.setLogLevel(ERROR); \ char buf[1024] = { 0 }; \ snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \ logger.log(buf); \ exit(-1); \ } while(0)#define LOG_FATAL(logmsgFormat, ...) \ do { \ Logger &logger = Logger::instance(); \ logger.setLogLevel(FATAL); \ char buf[1024] = { 0 }; \ snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \ logger.log(buf); \ } while(0) \ Logger &logger = Logger::instance(); \ logger.setLogLevel(DEBUG); \ char buf[1024] = { 0 }; \ snprintf(buf, 1024, logmsgFormat, ##__VA_ARGS__); \ logger.log(buf); \ } while(0)#else #define LOG_DEBUG(logmsgFormat, ...)#endif
- 防止派生类的拷贝构造
上一篇:怎么可以玩中国服务器?
下一篇:2024最新AI大模型产品汇总