该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。
其教学视频见:[C++高级教程]从零开始开发服务器框架(sylar)
上一篇:C++服务器框架开发7——日志系统LogFormatter_2
C++服务器框架开发8——日志系统LogFormatter_3/override/宏定义优化switchcase结构
目前进度
学习完第四个视频。Formatter还有一个视频,所以学完下个视频再把这几个类的关系理一下,否则可能难以很好理解。
要点:
- 对log.h中的LogEvent加了一些变量和函数,因为都还没实现,就先不细讲每个的功能了。
- 对log.h中的LogLevel加了一个level(UNKNOW),并且加了一个ToString成员函数(将日志级别转成文本输出)。
- 对log.h中的LogFormatte::format增加了一个参数Level,即把日志级别传进去。
- 在log.cc中,实现LogLevel::ToString函数,用了switch结构,其中使用了宏定义来简化,稍后会提到是怎么写的。
- 在log.cc中,同样的,给LogFormatte::format的实现加上参数level。
- 在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)定义无效。