本文的目的
实现类似于 golang 的隐式接口, 何为隐式接口, 那不得不先说下 c++ 的显示接口了, 我们知道 c++中,如果要实现一个接口必须显示的继承这个接口
#include <algorithm>
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
class speakBehavior {
public:
virtual void speak() = 0;
~speakBehavior(){}
};
class dog : public speakBehavior {
public:
void speak() override {
cout << "汪汪" << endl;
}
};
class cat : public speakBehavior {
public:
void speak() override {
cout << "喵喵" << endl;
}
};
int main() {
speakBehavior* sp = new dog;
sp->speak();
sp = new cat;
sp->speak();
}
输出
我么你可以发现, dog, cat 都显示实现了speakBehavior 接口
对于相同的行为, golang 的接口隐式实现又是什么样的呢, golang 规定,只要函数签名一样以及函数名一样那么你就实现了该接口, 让我们看看 golang 相同的代码
package main
import "fmt"
type speakBehavior interface {
speak()
}
type cat struct {
}
func(c cat) speak() {
fmt.Println("喵喵")
}
type dog struct {
}
func(d dog) speak() {
fmt.Println("汪汪")
}
func main() {
var s speakBehavior
s = dog{}
s.speak()
s = cat{}
s.speak()
}
输出
发现差别没有, c++ 是必须实现接口才能 interface* in = new Obj
在 golang 中, 只要你实现了接口的所有方法那么你就 可以interface in = obj{}, how cool
现在进入本文正题, c++ 能否实现类似的接口呢?
当然借用函数指针就行, 请看下面的代码
这次我们也没有实现接口,最终结果和 golang 类似,我们发现我们更加的灵活,我们甚至能做到,函数名不一致我们也能调用, 见上面的 shoutLoud 和 speak
故事到这里对于一般人差不多,该结束了。
下面我们发散的聊聊, 上面我们使用 function 模板来实现类 golang 的编程方式,甚至我们更加凶猛, 甚至函数名不一样都可以, 这个在一定程度可能有隐患
那么我们能不能加上函数名必须一样的这种限制了,那么下面将会讲讲怎么实现
建议看看https://blog.csdn.net/qq_34179431/article/details/116305213 再往下读
#include <algorithm>
#include <iostream>
using namespace std;
class car {
public:
void run() {
cout << "i am a car, move move move" << endl;
}
void print(string str) {
cout << "i am a car," << str << endl;
}
};
class crazyDog {
public:
void speak() {
cout << "i am a dog, 汪汪汪" << endl;
}
void speak(string word) {
cout << "i am a dog," << word << endl;
}
void run() {
cout << "i am a dog, move move move" << endl;
}
};
#define HAS_MEMBER(member) \
template<typename T, typename ... Args> \
struct has_member_##member { \
private: \
template<typename U> \
static auto Check(int)-> decltype(declval<U>().member(declval<Args>()...), true_type()); \
template<typename U> \
static false_type Check(...); \
public: \
constexpr static bool value = is_same<true_type, decltype(Check<T>(0))>::value; \
};
#define GET_SPECIFIC_CALLBACK(name) \
template<typename Obj, typename R, typename ...Args> \
auto name##CallBack(shared_ptr<Obj> obj) \
-> typename conditional< \
is_same< \
true_type, \
typename conditional<has_member_##name<Obj, Args...>::value, true_type, false_type>::type \
>::value, \
function<R(Args...)>, \
void \
>::type { \
R(Obj::*fun)(Args...) = &Obj::name; \
return [other = obj, f = fun](Args &&... args1) { \
return ((*other).*f)(forward<Args>(args1)...); \
}; \
}
#define REGISTER_CALLBACK(name) \
HAS_MEMBER(name) \
GET_SPECIFIC_CALLBACK(name)
REGISTER_CALLBACK(run)
REGISTER_CALLBACK(speak)
REGISTER_CALLBACK(print)
int main() {
auto p = runCallBack<car, void>(make_shared<car>());
p();
p = runCallBack<crazyDog, void>(make_shared<crazyDog>());
p();
p = speakCallBack<crazyDog, void>(make_shared<crazyDog>());
p();
auto d = speakCallBack<crazyDog, void, string>(make_shared<crazyDog>());
d("hello");
d = printCallBack<car, void, string>(make_shared<car>());
d("超速");
//car 没有实现 speak 接口,故报错
// p = speakCallBack<car, void>(make_shared<car>());
}
输出:
解释
1. 注册
REGISTER_CALLBACK(run) // 注册 run 方法 生成 runCallBack REGISTER_CALLBACK(speak) // 注册 speak, 生成 speakCallBack
2. 使用
// runCallBack<对象,返回值,参数列表> auto p = runCallBack<car, void>(make_shared<car>()); p(); p = runCallBack<crazyDog, void>(make_shared<crazyDog>()); p();
p = speakCallBack<crazyDog, void>(make_shared<crazyDog>()); p(); auto d = speakCallBack<crazyDog, void, string>(make_shared<crazyDog>()); d("hello");
综上,代码完成了, 文字不多, 希望各路大佬海涵。