​ 这边文章主要介绍了如何在linux上安装protobuf,以及如何使用。本文在此基础之上,做一些深入的讨论的总计。

1、for循环repeated字段:

1.1)对于基本类型的repeated:

可以通过属性()的方法获取到类型为const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >& XXX const;的只读集合引用,然后通过迭代器来遍历,对元素的修改不会影响到原集合本身;

也可以通过mutabl_属性()的方法获取到类型为::google::protobuf::RepeatedField< ::google::protobuf::int64 >* 的可修改的集合指针,然后通过迭代器遍历,对元素的修改会影响到集合本身。

示例:

1)pb结构:(my_test1.proto)

syntax = "proto2";
package video_stream;

message Test {
repeated int64 id = 1;
}

2)cpp代码:(my_test1.cpp)

#include <iostream>
#include <string.h>
#include <unordered_map>
#include <vector>
#include "my_test1.pb.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/text_format.h"

using namespace video_stream;
using namespace std;
using ::google::protobuf::RepeatedField;
using ::google::protobuf::int64;

int main() {
Test test;

//init
test.add_id(12);
test.add_id(13);
test.add_id(14);

cout << "size:" << test.id_size() << endl;
cout << "get:" << test.id(1) << endl;

//itera
const RepeatedField<int64>& id_vec = test.id();
for (auto itr = id_vec.begin();itr != id_vec.end(); ++itr){
*itr+=1000;
cout << "id:" << *itr << endl;
}
cout << "----------print------------" << endl;
std::string str;
google::protobuf::TextFormat::PrintToString(test, &str);
std::cout<< str <<std::endl;

//mutable itera
RepeatedField<int64>* id_vec1 = test.mutable_id();
for (auto itr = id_vec1->begin(); itr != id_vec1->end(); ++itr){
*itr+=100;
cout << "id:" << *itr <<endl;
}
cout << "----------print------------" << endl;
std::string new_str;
google::protobuf::TextFormat::PrintToString(test, &new_str);
std::cout<< new_str <<std::endl;


return 0;
}

 3)编译、运行:

protoc my_test1.proto --cpp_out=./
g++ -g -o run my_test1.cpp ./my_test1.pb.cc -I. -lprotobuf -pthread -std=c++11

./run

输出:

size:3
get:13
id:1012
id:1013
id:1014
----------print------------
id: 12
id: 13
id: 14

id:112
id:113
id:114
----------print------------
id: 112
id: 113
id: 114

1.2)对于复杂类型的repeated:

可以通过属性()的方法获取到类型为const ::google::protobuf::RepeatedPtrField< obj >& XXX const;的只读集合引用,然后通过迭代器来遍历,对元素的修改不会影响到原集合本身;

也可以通过mutabl_属性()的方法获取到类型为::google::protobuf::RepeatedPtrField< obj >* 的可修改的集合指针,然后通过迭代器遍历,对元素的修改会影响到集合本身。

示例:

1)pb结构(my_test2.proto):

syntax = "proto2";
package video_stream;

message Test {
repeated Obj objs = 1;
}

message Obj {
optional int64 id = 1;
optional string name = 2;
}

2)cpp代码(my_test2.cpp):

#include <iostream>
#include <string.h>
#include "my_test2.pb.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/text_format.h"

using namespace video_stream;
using namespace std;
using ::google::protobuf::RepeatedPtrField;
using ::google::protobuf::int64;


void init(Test& test) {
Obj* o;
o = test.add_objs();
o->set_id(1);
o->set_name("o1");

o = test.add_objs();
o->set_id(2);
o->set_name("o2");
}
int main() {
Test test;

//init
init(test);

cout << "size:" << test.objs_size() << endl;
cout << "get:" << test.objs(1).name() << endl;

//itera
const RepeatedPtrField<Obj>& obj_vec = test.objs();
for (auto itr = obj_vec.begin();itr != obj_vec.end(); ++itr){
itr->set_id(itr->id()+1000);
cout << "id:" << itr->id() <<",name:" << itr->name() << endl;
}
cout << "----------print------------" << endl;
std::string str;
google::protobuf::TextFormat::PrintToString(test, &str);
std::cout<< str <<std::endl;

//mutable itera
RepeatedPtrField<Obj>* obj_vec1 = test.mutable_objs();
for (auto itr = obj_vec1->begin(); itr != obj_vec1->end(); ++itr){
itr->set_id(itr->id()+100);
cout << "id:" << itr->id() <<",name:" << itr->name() <<endl;
}
cout << "----------print------------" << endl;
std::string new_str;
google::protobuf::TextFormat::PrintToString(test, &new_str);
std::cout<< new_str <<std::endl;


return 0;
}

3)编译运行:

protoc ./my_test2.proto --cpp_out=./
g++ -g -o run my_test2.cpp ./my_test2.pb.cc -I. -lprotobuf -pthread -std=c++11

./run

输出:

size:2
get:o2
id:1001,name:o1
id:1002,name:o2
----------print------------
objs {
id: 1
name: "o1"
}
objs {
id: 2
name: "o2"
}

id:101,name:o1
id:102,name:o2
----------print------------
objs {
id: 101
name: "o1"
}
objs {
id: 102
name: "o2"
}

1.3)上面都是通过迭代器遍历的,当然也可以通过for循环遍历:

对于对象类型的repeated,还可以在for循环中通过mutbale_属性(i)获得可修改的属性对象指针,对元素的修改会影响到集合本身;

对于基本类型的repeated,在for循环中只能通过属性(i)只读方式获取元素;

//只读的
for (int i=0;i<test.objs_size();i++){
const Obj& o = test.objs(i);
o.set_id(o.id()-1000);
cout << "id:" << o.id() <<",name:" << o.name() << endl;
}
cout << "----------for-print------------" << endl;
std::string str1;
google::protobuf::TextFormat::PrintToString(test, &str1);
std::cout<< str1 <<std::endl;


//可以修改的
for (int i=0;i<test.objs_size();i++){
Obj* o1 = test.mutable_objs(i);
o1->set_id(o1->id()-100);
cout << "id:" << o1->id() <<",name:" << o1->name() << endl;
}

cout << "----------mutable-for-print------------" << endl;
std::string new_str1;
google::protobuf::TextFormat::PrintToString(test, &new_str1);
std::cout<< new_str1 <<std::endl;

上面第一种方式对元素修改不会影响到集合;第二种对元素的修改会影响到集合。


2、枚举的使用:

message Person {
enum PhoneType { //枚举消息类型
MOBILE = 0; //proto3版本中,首成员必须为0,成员不应有相同的值
HOME = 1;
WORK = 2;
}

message PhoneNumber {
string number = 1;
PhoneType type = 2;
}

string name = 1; //姓名
int32 id = 2; //id
string email = 3; //邮件
repeated PhoneNumber phones = 4; //phones为数组
}

message AddressBook{
repeated Person people = 1;
}

AddressBook obj;
Person *p1 = obj.add_people(); //新增加一个Person
p1->set_name("mike");
p1->set_id(1);
p1->set_email("mike@qq.com");

Person::PhoneNumber *phone1 = p1->add_phones(); //增加一个phone
phone1->set_number("110");
phone1->set_type(Person::MOBILE);

Person::PhoneNumber *phone2 = p1->add_phones(); //增加一个phone
phone2->set_number("120");
phone2->set_type(Person::HOME);

//新增一个person
Person *p2 = obj.add_people(); //新增加一个Person
p2->set_name("...");

参考:​​javascript:void(0)​

3、CopyFrom、Swap方法:

对于对象类型的,可以使用mutable_XXX 方式获取对象指针,然后设置对象属性,也可以使用copyFrom直接拷贝,也可以使用Swap进行交换。

直接看一个例子:

1)pb结构:(my_test3.proto)

syntax = "proto2";
package video_stream;

message Test {
optional Obj obj = 1;
}

message Obj {
optional int64 id = 1;
optional string name = 2;
}

2)cpp代码:(my_test3.cpp)

#include <iostream>
#include <string.h>
#include "my_test3.pb.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/text_format.h"

using namespace video_stream;
using namespace std;
using ::google::protobuf::RepeatedPtrField;
using ::google::protobuf::int64;


void init(Test& test) {
Obj* o = test.mutable_obj();
o->set_id(1);
o->set_name("o1");
}
void printLog(Test& test) {
std::string str;
google::protobuf::TextFormat::PrintToString(test, &str);
std::cout<< str <<std::endl;
}
int main() {
Test test;

//init
init(test);

cout << "----------print------------" << endl;
printLog(test);

//copy from
Obj o1;
o1.set_id(2);
o1.set_name("o2");

test.mutable_obj()->CopyFrom(o1);
cout << "----------copyfrom-print------------" << endl;
printLog(test);

//swap
Obj o2;
o2.set_id(99);
o2.set_name("o99");
test.mutable_obj()->Swap(&o2);
cout << "----------swap-print------------" << endl;
printLog(test);
cout << "----------obj-print------------" << endl;
std::string str;
google::protobuf::TextFormat::PrintToString(o2, &str);
std::cout<< str <<std::endl;

return 0;
}

3)编译、运行:

protoc ./my_test3.proto --cpp_out=./
g++ -g -o run my_test3.cpp ./my_test3.pb.cc -I. -lprotobuf -pthread -std=c++11
./run

输出:

----------print------------
obj {
id: 1
name: "o1"
}

----------copyfrom-print------------
obj {
id: 2
name: "o2"
}

----------swap-print------------
obj {
id: 99
name: "o99"
}

----------obj-print------------
id: 2
name: "o2"

4、总结:

1)optional修饰的基本类型:

  • set_属性名(val) :修改属性值;
  • 属性名():获取属性值,返回类型是::google::protobuf::int64;

2)optional修饰的对象类型:

  • 属性名():返回只读的属性类型对象的引用,属性类型是指pb中定义的对象;
  • mutable_属性名():返回可修改的属性类型对象的指针,属性类型是指pb中定义的对象;

3)repeated修饰的基本类型:

  • add_属性名(val):向属性集合中添加元素;
  • 属性名_size():获取集合大小;
  • 属性名(i):返回集合中某一个元素,返回类型::google::protobuf::int64;
  • 属性名():返回只读的整个集合的引用,返回的集合类型是const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&,可以使用iterator来迭代遍历;
  • mutable_属性():返回可修改的整个集合的指针,返回的集合类型是::google::protobuf::RepeatedField< ::google::protobuf::int64 >*,可以使用iterator来迭代遍历;

4)repeated修饰的对象类型:

  • add_属性名():返回可修改的属性类型对象的指针(集合中的一个元素),属性类型是指pb中定义的对象;
  • 属性名_size():获取集合大小;
  • 属性名(i):返回集合中某一个元素,返回的是只读的属性类型对象的引用,属性类型是指pb中定义的对象;
  • mutable_属性名(i):返回集合中某一个元素,返回的是可修改的属性类型对象的指针,属性类型是指pb中定义的对象;
  • 属性名():返回只读的整个集合的引用,集合类型是const ::google::protobuf::RepeatedPtrField< pb定义的对象>& XXX const;,可以使用iterator来迭代遍历;
  • mutable_属性名():返回可修改的整个集合的指针,集合类型是::google::protobuf::RepeatedPtrField< pb定义的对象>*,可以使用iterator来迭代遍历;

:对于repeated属性,通过属性名()方法返回的只读集合对象,是一个const引用类型,这样做的好处是在赋值时会少一次拷贝构造函数、析构函数的调用,又因为函数返回值是一个右值,所以引用必须是一个const类型的。对于mutable_属性名()方法返回一个可修改的集合对象,是一个指针类型,这样做好处也是为了较少拷贝构造函数、析构函数的调用,但这时又不能是const引用,所以只能是返回指针。