C++服务器框架开发8——日志系统LogFormatter_3/override/宏定义优化switchcase结构

该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。
其教学视频见:[C++高级教程]从零开始开发服务器框架(sylar)

上一篇:C++服务器框架开发7——日志系统LogFormatter_2

C++服务器框架开发8——日志系统LogFormatter_3/override/宏定义优化switchcase结构

目前进度

学习完第四个视频。Formatter还有一个视频,所以学完下个视频再把这几个类的关系理一下,否则可能难以很好理解。
要点:

  1. 对log.h中的LogEvent加了一些变量和函数,因为都还没实现,就先不细讲每个的功能了。
    在这里插入图片描述
  2. 对log.h中的LogLevel加了一个level(UNKNOW),并且加了一个ToString成员函数(将日志级别转成文本输出)。
    在这里插入图片描述
  3. 对log.h中的LogFormatte::format增加了一个参数Level,即把日志级别传进去。
    在这里插入图片描述
  4. 在log.cc中,实现LogLevel::ToString函数,用了switch结构,其中使用了宏定义来简化,稍后会提到是怎么写的。
    在这里插入图片描述
  5. 在log.cc中,同样的,给LogFormatte::format的实现加上参数level。
    在这里插入图片描述
  6. 在log.cc中,定义了两个继承了LogFormatter::FormatItem的子类,MessageFormatItem和LevelFormatItem。(从那些蓝色注释就可以看到,其实还有好多个子类没实现。LogFormatter::m_items含有各种不同类型的Item,每种类型都需要定义一个子类。200~206行只是在实现这些子类时方便查看一些变量,后面实现完子类后就删掉了。)
    在这里插入图片描述

关键字override

由于MessageFormatItem和LevelFormatItem中在覆写format函数时,除了这个关键字,所以学习下。
参考自文章1

**问题:**没有覆写成功导致没有实现想要的继承效果。(因为子类的函数的函数签名漏写了1个const)

#ifndef __HELLOWORLD__
#define __HELLOWORLD__
#include<iostream>
#endif 

struct Base {
	virtual void doSomething(int i) const {
		std::cout << "This is from Base with " << i << std::endl;
	}
};

struct Derivied : Base {
	virtual void doSomething(int i) { //这里没有加const,所以它和Base的doSomething没有相同的函数签名
		std::cout << "This is from Derived with " << i << std::endl;
	}
};

void letDoSomething(Base& base) {
	base.doSomething(419);
}

int main() {
	Derivied d;
	letDoSomething(d);  //输出结果: "This is from Base with 419"
	return 0;
}

在这里插入图片描述

解决:C++11引入了override关键字。
在这里插入图片描述
正确写法:

struct Derivied : Base {
	void doSomething(int i) const override { //无需在前面加virtual了
		std::cout << "This is from Derived with " << i << std::endl;
	}
};

在这里插入图片描述

注:子类的虚函数加virtual的目的除了是给子类的子类继承外,还有就是提醒程序员这是一个覆写的虚函数,当用了override后就不需要用virtual来提醒了。

宏定义优化switchcase结构

先把这段代码单独拿出来看看效果。

#ifndef __HELLOWORLD__
#define __HELLOWORLD__
#include<iostream>

#endif 


class LogLevel {
public:
	enum Level {
		/// 未知级别
		UNKNOW = 0,
		/// DEBUG 级别
		DEBUG = 1,
		/// INFO 级别
		INFO = 2,
		/// WARN 级别
		WARN = 3,
		/// ERROR 级别
		ERROR = 4,
		/// FATAL 级别
		FATAL = 5
	};

	static const char* ToString(LogLevel::Level level);
};
const char* LogLevel::ToString(LogLevel::Level level) {
	switch (level) {
#define XX(name) \
    case LogLevel::name: \
        return #name; \
        break;

		XX(DEBUG);
		XX(INFO);
		XX(WARN);
		XX(ERROR);
		XX(FATAL);
#undef XX
	default:
		return "UNKNOW";
	}
	return "UNKNOW";
}
int main() {
	LogLevel mylevel;
	LogLevel::Level oneLevel = LogLevel::ERROR;

	std::cout << mylevel.ToString(oneLevel);

	return 0;
}

在这里插入图片描述
大致解释:#define XX(name) case LogLevel::name: return #name; break;定义了XX(name)宏,可以使用XX(A)来实现 case LogLevel::A: return #A; break;
疑惑点1:return #name为什么就可以把那个名字返回成const char*类型?
解答1:#将其后面的东西转化为字符串,示例代码:

#ifndef __HELLOWORLD__
#define __HELLOWORLD__
#include<iostream>
#define TO_STRING(str) #str
#endif 

int main() {
	std::cout << TO_STRING(this is a string) << std::endl;
	return 0;
}

在这里插入图片描述

疑惑点2:undef是什么?
解答2: 取消该定义,即XX(name)定义无效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小欣CZX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值