假设我有以下回调类:
class LogCallback {
public:
virtual void sendLog(std::string log) = 0;
virtual void setErrorCode(int code) = 0;
};
我有引擎接受回调实现:
class Engine {
public:
Engine();
virtual ~Engine();
void setCallback(LogCallback* callback);
void start();
private:
LogCallback* logCallback;
};
现在我可以创建一个实现类:
class OutLogger : public LogCallback {
void sendLog(std::string log) {
cout << "out: " << log << endl;
}
void setErrorCode(int code) {
sendLog("error code " + std::to_string(code));
}
};
并使用它:
int process() {
Engine engine;
OutLogger out;
engine.setCallback(&out);
engine.start();
}
在C ++ 11中,我也可以使用匿名本地类:
int anonymous() {
Engine engine;
class : public LogCallback {
void sendLog(std::string log) {
cerr << "err: " << log << endl;
}
void setErrorCode(int code) {
sendLog("error code " + std::to_string(code));
}
} err;
engine.setCallback(&err);
engine.start();
}
现在有一个问题:我可以在函数调用中没有明确的匿名类吗?
如果是Java,我会这样做:
public class AnonymousClass {
private abstract class LogCallback {
abstract void sendLog(String log);
abstract void setErrorCode(int code);
}
private class Engine {
public void setCallback(LogCallback callback) {
this.callback = callback;
}
public void start() {
if (callback != null) {
callback.sendLog("Starting...");
}
}
private LogCallback callback;
}
public void process() {
Engine engine = new Engine();
engine.setCallback(new LogCallback() {
@Override
void sendLog(String log) {
System.out.println("out: " + log);
}
@Override
void setErrorCode(int code) {
sendLog("error code " + code);
}
});
engine.start();
}
public static void main(String[] args) {
AnonymousClass example = new AnonymousClass();
example.process();
}
}
答案 0 :(得分:2)
霍尔特上面的评论是正确的。在Java的new X() { ... }
之类的表达式中声明新类型的唯一方法是lambda表达式,并且不能从抽象基类派生它。
C ++的方法是停止所有OOP继承ickiness并使用函数模板,或者使用类型擦除std::function
的函数,因此它接受任何具有合适调用签名的可调用,然后你可以使用lambda。
例如:
class Engine {
public:
enum class LogType { String, ErrorCode };
using LogCallback = std::function<void(LogType, std::string, int)>;
Engine();
virtual ~Engine();
void setCallback(LogCallback callback) { logCallback = callback; }
void start() {
if (logCallback)
logCallback(LogType::String, "Starting...", 0);
}
private:
LogCallback logCallback;
};
int anonymous() {
Engine engine;
engine.setCallback([](Engine::LogType t, std::string log, int code) {
if (t == Engine::LogType::ErrorCode)
log = "error code " + std::to_string(code);
cerr << "err: " << log << endl;
});
engine.start();
}
(LogCallback类型的更好定义是:
using LogCallback = std::function<void(std::variant<std::string, int>)>;
但我们还没有在C ++中使用variant
。)
答案 1 :(得分:1)
您无法实现接口,但您可以创建具有回调函数作为参数的泛型类:
class GenericLogCallback : public LogCallback {
public:
GenericLogCallback(std::function<void (std::string)> sendlog,
std::function<void (int)> seterrorcode) : sendLog_(std::move(sendlog)),
setErrorCode_(std::move(seterrorcode)) {}
virtual void sendLog(std::string log) override {
if(sendLog_) sendLog_(log);
}
virtual void setErrorCode(int code) override {
if(setErrorCode_) setErrorCode_(code);
}
private:
std::function<void (std::string)> sendLog_;
std::function<void (int)> setErrorCode_;
};
...
GenericLogCallback err([](std::string){},[](int){});
engine.setCallback(&err);
答案 2 :(得分:1)
使用std::function
在此处发布的答案很好,但如果您非常关注性能,可以直接存储仿函数(可能是std::bind()
或C-的结果)做得更好样式函数指针或lambdas):
template <typename SendLog, typename SetErrorCode>
class GenericLogger : public LogCallback {
public:
GenericLogger(SendLog sender, SetErrorCode setter)
: m_sender(sender), m_setter(setter) {}
void sendLog(std::string log) override {
m_sender(log);
}
void setErrorCode(int code) override {
m_setter(code);
}
SendLog m_sender;
SetErrorCode m_setter;
};
template <typename SendLog, typename SetErrorCode>
GenericLogger<SendLog, SetErrorCode> makeLogger(SendLog sender, SetErrorCode setter) {
return GenericLogger<SendLog, SetErrorCode>(sender, setter);
}
void sendLog(std::string log) {
std::cout << "out: " << log << std::endl;
}
void setErrorCode(int code) {
sendLog("error code " + std::to_string(code));
}
int main()
{
Engine engine;
auto out = makeLogger(
[](std::string s){std::cout << "lambda: " << s << '\n';},
setErrorCode);
engine.setCallback(&out);
engine.start();
}
以上内容避免使用std::function
,除非makeLogger()
的实际参数属于该类型。这通过调用给定的仿函数来减少开销,而不是总是存储std::function
。
答案 3 :(得分:1)
您可以做的一件事是创建一个允许使用lambdas的包装类:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<table id="usersdata" > </table>