问题:
我有一组像Database一样的类。我需要根据他们的操作码解包某些响应。
eq:操作码:01 要求:A
从请求A解压缩响应,我创建了一个类A.同样,我没有类。
我需要根据操作码将byteArray解压缩到其中一个类中。
C ++中是否有任何机制可以实现某种映射,我可以在其中查找操作码并选择要解压缩的类/响应
PS:非常喜欢可读的解决方案和一些解释。
我对JAVA知之甚少,但在JAVA中,我猜我们有使用对象类型,类类型等的机制。
由于
答案 0 :(得分:5)
您可以实现工厂:从操作码(作为整数/枚举),类名(作为字符串)等映射到动态实例化类的函数:
enum Opcode {
OpFoo,
OpBar,
OpQux,
};
// this should be a pure virtual ("abstract") base class
class Operation {
// ...
};
class OperationFoo: public Operation {
// this should be a non-abstract derived class
};
class OperationBar: public Operation {
// this should be a non-abstract derived class too
};
std::unordered_map<Opcode, std::function<Operation *()>> factory {
{ OpFoo, []() { return new OperationFoo; } }
{ OpBar, []() { return new OperationBar; } }
{ OpQux, []() { return new OperationQux; } }
};
Opcode opc = ... // whatever
Operation *objectOfDynamicClass = factory[opc]();
作为奖励,您可以(并且可能应该)使用智能指针(std::unique_ptr
或std::shared_ptr
)而不是原始指针在工厂lambda函数的返回类型和您使用的其他位置抽象类。
答案 1 :(得分:2)
您应该了解C ++中的类仅在编译时存在。在运行时,您只有vtables,可能还有RTTI,但这些类已被遗忘。 (这在Java中是不同的,类在运行时存在并且为JVM和class loaders所知。)
您可能想要使用factory pattern。例如,您可能(在C++11中)有一个全局映射,将某些名称(或您的操作码)与工厂函数构建实例相关联。 this answer提供了一些示例代码。
在某些操作系统上(或使用POCO等某些库),您可以使用dynamic loading&amp; plugin设施dlopen(3)等设施Posix上的dlsym
(例如Linux)。请注意,dlsym
可以通过其unmangled)名称访问extern "C"
函数。另请参阅this。
答案 2 :(得分:0)
一个非常模板化的解决方案,使用如下:
class A {virtual ~A() = 0;};
inline A::~A() = default;
class B : A {};
class C : A {};
class D : B {};
// Define the factory
DEFINE_FACTORY(A, B, C, D)
// Want the factory?
factory<A> a_factory;
A* ap = a_factory(1, 0, 1, 2, 3); // Creates a C, passing 0,1,2,3 to the ctor
delete ap;
// Or directly?
make<std::unique_ptr>(1,0,1,2,3); // Creates a C, passing 0,1,2,3 to the ctor
// Immediately destroyed because the `std::unique_ptr` was not saved.
这里的模板代码使其成为可能:
#include <utility>
#include <memory>
#include <exception>
template<class I, class... X> struct factory_base {
template<class... ARGS> inline I* operator()(int i, ARGS&&... args) {
return make(i, std::forward<ARGS>(args)...);
}
template<class... ARGS> using maker_t = I*(*)(ARGS...);
template<class... ARGS> static I* make(int i, ARGS&&... args) {
constexpr maker_t<ARGS...> maker[] = {make_helper<X, ARGS...>()...};
if(i < sizeof...(X) && maker[i])
return maker[i](std::forward<ARGS>(args)...);
throw std::invalid_argument("The selected class cannot be constructed thus.");
}
template<class Y, class... ARGS> inline static constexpr maker_t<ARGS...>
make_helper(...) {return nullptr;}
template<class Y, class... ARGS> inline static constexpr auto make_helper()
-> decltype(new Y(std::declval<ARGS>()...), maker_t<ARGS...>(0))
{return static_cast<maker_t<ARGS...>>(
[](ARGS&&... args){return new Y(std::forward<ARGS>(args)...);});}
};
template<class I> class factory;
#define DEFINE_FACTORY(A, ...) template<> struct factory<A> : \
factory_base<A, __VA_ARG__> {}
template<class I, class... ARGS> std::unique_ptr<I> make(ARGS&&... args) {
return factory<I>()(std::forward<ARGS>(args)...);
}