【发布时间】:2014-01-26 04:39:44
【问题描述】:
我正在设计一个包含多个模块的工具包。我试图使模块尽可能独立,因此它们甚至可以独立编译(例如作为库)。
其中一个模块是logging,另一个是geometry。现在geometry 中的一个基类接收一个指向logging 对象的指针,然后用它来记录数据:
#include "../logging/logger.h"
class GeometryBase {
public:
//...
void do_something() { if (logger) logger->debug("doing something"); }
void setLogger(Logger* logger) {//...};
private:
Logger* logger = nullptr;
};
所以为此我需要包含../logging/logger.h,这意味着编译这个模块需要logging 标头。有没有办法解决这个问题,所以即使 logging 标头不存在,它仍然可以编译?
现在我可以考虑使用宏在预处理期间使与日志记录相关的所有部分成为条件。喜欢:
#ifdef USE_LOGGING
#include "../logging/logger.h"
#endif
class GerometryBase {
//...
void do_something() { if (logger) _log("doing something"); }
#ifdef USE_LOGGING
void _log(const std::string& s) {//...}
Logger* logger = nullptr;
#else
void _log(const std::string& s) {// do nothing}
void* logger = nullptr;
#endif
}; // class
有没有更好/更清洁的方法来做到这一点?是否有针对此类设计的推荐指南或最佳做法?
================================================ ====================================
更新
这是一个使用函数指针的示例实现(基于 rioki 的想法),它确实有助于解耦对象:
obj.h
#ifndef MYOBJ_H_
#define MYOBJ_H_
#include <iostream>
class MyObj {
public:
MyObj() { std::cout << "constructing MyObj" << std::endl; }
void setLogger( void (*p)(const char*, int) ) {
logger = p;
}
void do_somthing() {
if (logger) {
logger("this is a debug message", 1);
}
}
private:
void (*logger)(const char*, int ) = nullptr;
};
#endif
logger.h
#ifndef LOGGER_H
#define LOGGER_H
void logger(const char* , int);
#endif
logger.cpp
#include <iostream>
#include "logger.h"
void logger(const char* str, int lvl) {
std::cout << "level " << lvl << " " << str << std::endl;
}
main.cpp
#include "logger.h"
#include "obj.h"
int main() {
MyObj obj;
obj.setLogger(logger);
obj.do_somthing();
return 0;
}
输出:
constructing MyObj
level 1 this is a debug message
【问题讨论】:
-
你真的应该像 rioki 建议的那样使用 std::function 而不是函数指针。它使您的代码更易于阅读,并允许您清楚地表达您的意图。