一 动态编译
前文介绍了Protobuf的安装及编译方法,不过protobuf不仅提供了使用protoc进行静态编译的方法,也提供了动态编译的方法
动态编译 也就是说无须编译
.proto
生成.pb.cc
和.pb.h
需要使用protobuf中提供的两个头文件, protobuf中头文件的位置
/usr/local/include/google/protobuf
google/protobuf/compiler/importer.h
以及google/protobuf/dynamic_message.h
先看代码示例
#include <iostream>#include <string>#include <google/protobuf/compiler/importer.h>#include <google/protobuf/dynamic_message.h>class MyErrorCollector: public google::protobuf::compiler::MultiFileErrorCollector { virtual void AddError(const std::string & filename, int line, int column, const std::string & message){ // define import error collector printf("%s, %d, %d, %s\n", filename.c_str(), line, column, message.c_str()); } };int main(){ google::protobuf::compiler::DiskSourceTree sourceTree; // source tree sourceTree.MapPath("", "/home/szw/code/protobuf/tmp2"); // initialize source tree MyErrorCollector errorCollector; // dynamic import error collector google::protobuf::compiler::Importer importer(&sourceTree, &errorCollector); // importer importer.Import("test.proto"); // find a message descriptor from message descriptor pool const google::protobuf::Descriptor * descriptor = importer.pool()->FindMessageTypeByName("lm.helloworld"); if (!descriptor){ perror("Message is not found!"); exit(-1); } // create a dynamic message factory google::protobuf::DynamicMessageFactory * factory = new google::protobuf::DynamicMessageFactory(importer.pool()); // create a const message ptr by factory method and message descriptor const google::protobuf::Message * tmp = factory->GetPrototype(descriptor); // create a non-const message object by const message ptr // define import error collector google::protobuf::Message * msg = tmp->New(); return 0; }
头文件
<google/protobuf/compiler/importer.h>
包含了编译器对象相关头文件
<google/protobuf/dynamic_message.h>
包含了Message_Descriptor
和Factory
相关
首先初始化一个
DiskSourceTree
对象, 指明目标.proto
文件的根目录创建一个
MyErrorCollector
对象, 用于收集动态编译过程中产生的编译bug, 该对象需要根据proto提供的纯虚基类派生, 并需要重写其中的纯虚函数, 使之不再是一个抽象类初始化一个
Importer
对象, 用于动态编译, 将DiskSourceTree
和MyErrorCollector
的地址传入将目标
.proto
动态编译, 并加入编译器池中可以通过
FindMessageTypeName()
和消息名, 来获取到目标消息的Message_Descriptor
创建动态工厂, 并利用工厂方法
GetPrototype
和目标消息的Message_Descriptor
获取一个指针const message *
利用消息实例指针的
New()
方法获取到non-const message ptr
二 类型反射
类型反射即是根据字段的名称获取到字段类型的一种机制
protobuf自身便配备了类型反射机制
需要头文件
<google/protobuf/descriptor.h>
与<google/protobuf/message.h>
下面的示例,结合了动态编译以及类型反射机制
代码解析:
首先使用动态编译机制,将test1.proto与test2.proto两个文件动态编译进编译池
根据消息名获取到目标消息的descriptor
创建一个动态工厂,并利用消息的descriptor获取到
const Message * tmp
利用
const Message * tmp
的方法New()
获取Message * msg
根据msg获取反射器
Reflection
对象利用descriptor可以遍历各个字段, 并利用descriptor的
cpp_type()
方法获取到每个字段的类型, 并借此进行反射填充
代码示例
proto文件
// @file test1.protosyntax = "proto3"; package lm; message Player { int32 id = 1; string name = 2; repeated string hero = 3; }
// @file test2.protosyntax = "proto3";import "test1.proto"; package lm; message Game{ repeated Player player = 1; string gameName = 2; };
cpp
// @file test.cpp#include <iostream>#include <string>#include <google/protobuf/compiler/importer.h> // Importer DiskSourceTree MultiFileErrorCollector#include <google/protobuf/dynamic_message.h> // DynamicMessageFactory #include <google/protobuf/descriptor.h> // Desctriptor FiledDescriptor ... all descriptor#include <google/protobuf/message.h> // Message Reflection MessageFactoryclass MyErrorCollector: public google::protobuf::compiler::MultiFileErrorCollector { virtual void AddError(const std::string & filename, int line, int column, const std::string & message){ // define import error collector printf("%s, %d, %d, %s\n", filename.c_str(), line, column, message.c_str()); } };int main(){ google::protobuf::compiler::DiskSourceTree sourceTree; // source tree sourceTree.MapPath("", "./"); // initialize source tree MyErrorCollector errorCollector; // dynamic import error collector google::protobuf::compiler::Importer importer(&sourceTree, &errorCollector); // importer importer.Import("test1.proto"); importer.Import("test2.proto"); // find a message descriptor from message descriptor pool const google::protobuf::Descriptor * descriptor = importer.pool()->FindMessageTypeByName("lm.Game"); if (!descriptor){ perror("Message is not found!"); exit(-1); } // create a dynamic message factory google::protobuf::DynamicMessageFactory * factory = new google::protobuf::DynamicMessageFactory(importer.pool()); // create a const message ptr by factory method and message descriptor const google::protobuf::Message * tmp = factory->GetPrototype(descriptor); // create a non-const message ptr object by const message ptr // define import error collector google::protobuf::Message * msg = tmp->New(); // get a reflection by msg const google::protobuf::Reflection * reflection = msg->GetReflection(); // travel the message by message_descriptor for (int i=0; i<descriptor->field_count(); ++i){ const google::protobuf::FieldDescriptor * fieldDescriptor = descriptor->field(i); if (fieldDescriptor->is_repeated()){ switch (fieldDescriptor->cpp_type()){ case google::protobuf::FieldDescriptor::CPPTYPE_INT32: { reflection->AddInt32(msg, fieldDescriptor, 10); break; } case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { reflection->AddString(msg, fieldDescriptor, "abc"); } case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { printf("Here is a repeadted message: %s\n", fieldDescriptor->full_name().c_str()); } case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_INT64: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: { break; } } }else{ switch (fieldDescriptor->cpp_type()){ case google::protobuf::FieldDescriptor::CPPTYPE_INT32: { reflection->SetInt32(msg, fieldDescriptor, 10); break; } case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { reflection->SetString(msg, fieldDescriptor, "abc"); } case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { printf("Here is a message: %s\n", fieldDescriptor->full_name().c_str()); } case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_INT64: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: { break; } } } } printf("\nmsg\n"); msg->PrintDebugString(); return 0; }
作者:neilzwshen
链接:https://www.jianshu.com/p/e692a6a2f78e
共同学习,写下你的评论
评论加载中...
作者其他优质文章