﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-egametang</title><link>http://www.cppblog.com/egametang/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 09 Apr 2026 06:14:15 GMT</lastBuildDate><pubDate>Thu, 09 Apr 2026 06:14:15 GMT</pubDate><ttl>60</ttl><item><title>C++ protobuf 不仅仅是序列化……</title><link>http://www.cppblog.com/egametang/archive/2012/04/12/171063.html</link><dc:creator>唐诗</dc:creator><author>唐诗</author><pubDate>Thu, 12 Apr 2012 04:09:00 GMT</pubDate><guid>http://www.cppblog.com/egametang/archive/2012/04/12/171063.html</guid><wfw:comment>http://www.cppblog.com/egametang/comments/171063.html</wfw:comment><comments>http://www.cppblog.com/egametang/archive/2012/04/12/171063.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/egametang/comments/commentRss/171063.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/egametang/services/trackbacks/171063.html</trackback:ping><description><![CDATA[<div><span style="font-size: 12px;">一点小牢骚 cppblog和博客园是啥关系呢？同两边的人交流交流 难道我两边都要发一遍？<br /><br />&nbsp; &nbsp; &nbsp; C++中protobuf是个常用的序列化库，网络消息发送，消息解析都十分方便，xml可以干的，它都能干。但是它绝不仅仅是序列化库。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">简单的说，protobuf给C++增加了C# attribute的功能。C++从此就有了元数据了！会c#的同学肯定明白了这句话的意义了。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">一. protobuf用作配置文件：</span></div><div><span style="font-size: 12px;">protobuf提供了一种textformat的序列化格式，类似json格式，清晰易读。比如一棵行为树节点描述文件：</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">数据定义为：</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">message BehaviorNodeConf</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>required int32 type = 1;</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>// 条件需要的参数</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>repeated int32 args = 2;</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>// 包含多个子节点</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>repeated BehaviorNodeConf node = 3;</span></div><div><span style="font-size: 12px;">};</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">message BehaviorTreeConf</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>// 行为树类型: AI, ON_HIT, ON_HITTED ...</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>required int32 type = 1;</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>// 行为树节点</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>required BehaviorNodeConf node = 2;</span></div><div><span style="font-size: 12px;">};配置文件为：</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">type: 5</span></div><div><span style="font-size: 12px;">node:</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>type: 1</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>node:</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>type: 101</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>args: 2</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>}</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>node:</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>type: 1</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>node:</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>type: 1001</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>args: 0</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>args: 100</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>}</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>node:</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>type: 1001</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>args: 1</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>args: -100</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>}</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>}</span></div><div><span style="font-size: 12px;">} 以下两行代码即可解析这个配置文件：BehaviorTreeConf conf;</span></div><div><span style="font-size: 12px;">google::protobuf::TextFormat::ParseFromString(fileContent, &amp;conf);二. protobuf的反射用法</span></div><div><span style="font-size: 12px;">很多人都说C++很难做Orm，因为没有反射等等，有了protobuf这一切都不是问题了，如下：</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">select操作：自动生成select语句，查询一条记录把它保存到person变量里面</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>try</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>DbHelper dbHelper("tcp://127.0.0.1:3306", "root", "111111");</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>DbResultPtr result = dbHelper.Execute(</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">				</span>Select&lt;Person&gt;(Column("*")).</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">				</span>Where(Column("age") &gt; 10)</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>);</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>auto person = boost::make_shared&lt;Person&gt;();</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>result-&gt;One(person);</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">		</span>ASSERT_EQ(26, person-&gt;age());</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>}</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>catch (const Exception&amp; e)</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>} &nbsp;update操作: 自动生成update语句，这段代码是从我的单元测试里面抠出来的，大家明白意思就行了TEST_F(UpdateTest, Update_Where)</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>std::string expectedSql;</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>expectedSql =</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>"update Egametang.Person "</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>"set guid = 1, age = 18, comment = 'a good student!' "</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">			</span>"where age &gt; 10";</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>Person person;</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>person.set_guid(1);</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>person.set_age(18);</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>person.set_comment("a good student!");</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>Update update(person);</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>update.Where(Column("age") &gt; 10);</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>EXPECT_EQ(expectedSql, update.ToString());</span></div><div><span style="font-size: 12px;">} 三.protbuf 类似c# attribute功能</span></div><div><span style="font-size: 12px;">看如下一段protobuf定义：import "google/protobuf/descriptor.proto";</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">extend google.protobuf.FileOptions&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional string my_file_option = 50000;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">extend google.protobuf.MessageOptions&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional int32 my_message_option = 50001;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">extend google.protobuf.FieldOptions&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional float my_field_option = 50002;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">extend google.protobuf.EnumOptions&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional bool my_enum_option = 50003;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">extend google.protobuf.EnumValueOptions&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional uint32 my_enum_value_option = 50004;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">extend google.protobuf.ServiceOptions&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional MyEnum my_service_option = 50005;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">extend google.protobuf.MethodOptions&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional MyMessage my_method_option = 50006;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">option (my_file_option) = "Hello world!";</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">message MyMessage&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; option (my_message_option) = 1234;</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional int32 foo = 1 [(my_field_option) = 4.5];</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; optional string bar = 2;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">enum MyEnum&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; option (my_enum_option) = true;</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; FOO = 1 [(my_enum_value_option) = 321];</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; BAR = 2;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">message RequestType {}</span></div><div><span style="font-size: 12px;">message ResponseType {}</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">service MyService&nbsp;</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; option (my_service_option) = FOO;</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; rpc MyMethod(RequestType) returns(ResponseType)&nbsp;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; {</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; // Note: &nbsp;my_method_option has type MyMessage. &nbsp;We can set each field</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; // &nbsp; within it using a separate "option" line.</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; option (my_method_option).foo = 567;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; option (my_method_option).bar = "Some string";</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; }</span></div><div><span style="font-size: 12px;">}protobuf中的option就是C#中的attribute，option同样可以放在message（同c#的class） service（同c#的方法） 以及message的field上面</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">四.游戏开发中如何利用protobuf的这功能呢？</span></div><div><span style="font-size: 12px;">1.策划使用protobuf作为配置文件，我可以在数据定义中设置某个字段的option为C#的哪个控件，</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">编辑器读到这个数据定义就可以直接生成一个控件，因此可以根据数据定义生成编辑器给策划填写数据。例如：</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">message BehaviorNodeConf</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>required int32 type = 1 [control = "textbox" max = 100 min = 0];</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>// 条件需要的参数</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>repeated int32 args = 2 [control = "textbox"];</span></div><div><span style="font-size: 12px;">}; 2.再如： 技能可以施放buff，每个buff都应该有一个关联的技能，那么策划填表的时候要填一个技能的proto表还要填一个buff的proto表，两张表策划很容易就填漏了我们可以加上一个约束，由编辑器去检查：message Spell</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>required int32 id = 1;</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>optional int32 buffId = 2 [ref = "Buff.id"];</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">message Buff</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>required int32 id = 1 [ref = "Spell.buffId"];</span></div><div><span style="font-size: 12px;"><span style="white-space:pre">	</span>optional int32 time = 2;</span></div><div><span style="font-size: 12px;">}编辑器填写一个buff会去检查是否有关联这个buff的技能存在，填技能的时候如果填了buff也要强制配置相应的buff，这样大大减少了配置错误，策划从此从填表错误中解脱出来。 &nbsp;策划爽了，程序员的爽还远吗？ 他好我也好！ protobuf写的一个简易orm,目前实现了select和update，其它的后续增加，原理是一样的代码地址： https://github.com/egametang/Egametang/tree/master/Cpp/Platform/Orm</span></div><img src ="http://www.cppblog.com/egametang/aggbug/171063.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/egametang/" target="_blank">唐诗</a> 2012-04-12 12:09 <a href="http://www.cppblog.com/egametang/archive/2012/04/12/171063.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>