当使用--cpp_out=命令行标志调用时,protocol buffer 编译器产生c++输出。--cpp_out=选项的参数是您希望编译器在其中编写c++输出的目录。编译器为每个.proto文件输入创建一个头文件和一个实现文件。输出文件的名称是通过获取.proto文件的名称并进行以下更改来计算的:
扩展名(.proto)被.pb.h或.pb替换。分别为头文件或实现文件。
proto路径(用--proto_path=或-I命令行标志指定)被输出路径(用--cpp_out=标志指定)替换。
例如,假设你像下面这样调用编译器:
protoc --proto_path=src --cpp_out=build/gen src/foo.proto src/bar/baz.proto
编译器将读取src/foo.proto和src/bar/baz.proto生成四个输出文件:build/gen/foo.pb.h, build/gen/foo.pb.cc, build/gen/bar/baz.pb.h, build/gen/bar/baz.pb.cc。如果需要,编译器会自动创建build/gen/bar目录,但它不会创建build或build/gen;它们必须已经存在。
Packages
如果.proto文件包含包声明,则文件的整个内容将被放置在相应的c++命名空间中。例如,给定包声明:
package foo.bar;
文件中的所有声明都将驻留在foo::bar命名空间中。
Messages
给出一个简单的消息声明:
message Foo {}
protocol buffer编译器生成一个名为Foo的类,它public派生自google::protobuf::Message。类是一个具体类,没有未实现的纯虚方法。默认情况下,Foo实现所有方法的专用版本以获得最大速度。但是,如果.proto文件包含以下行:
option optimize_for = CODE_SIZE;
那么Foo将只覆盖功能所需的最小方法集,这大大减少了生成代码的大小,但也降低了性能。或者,如果.proto文件包含:
option optimize_for = LITE_RUNTIME;
那么Foo将包括所有方法的快速实现,但将实现google::protobuf::MessageLite接口,该接口只包含Message方法的一个子集。特别是,它不支持描述符或反射。但是,在这种模式下,生成的代码只需要链接到libprotobuf-lite。(libprotobuf-lite。libprotobuf (Windows上的libprotobuf)。(libprotobuf.lib)。“精简”库比完整库小得多,更适合于资源受限的系统。
不应该创建自己的Foo子类。如果创建该类的子类并重写虚拟方法,则重写可能会被忽略,因为许多生成的方法调用被去虚拟化以提高性能。
Message接口定义了一些方法,这些方法允许您检查、操作、读取或写入整个消息,包括解析二进制字符串和序列化二进制字符串。
1.bool ParseFromString(const string& data):从给定的序列化二进制字符串(也称为有线格式)中解析消息。
2.bool SerializeToString(string* output) const:将给定的消息序列化为二进制字符串。
3. string DebugString():返回一个字符串,给出原型的text_format表示形式(应该只用于调试)。
除了这些方法,Foo类还定义了以下方法:
Foo():默认构造函数。
~Foo():默认析构函数。
Foo(const Foo& other):复制构造函数。
Foo(Foo&& other):移动构造函数。
Foo& operator=(const Foo& other):赋值操作符。
Foo& operator=(Foo&& other):移动赋值操作符。
void Swap(Foo* other):用另一条消息交换内容。
const UnknownFieldSet& unknown_fields() const:返回解析此消息时遇到的未知字段集。如果在.proto文件中指定了option optimize_for = LITE_RUNTIME,则返回类型更改为std::string&。
UnknownFieldSet* mutable_unknown_fields():返回一个指针,指向解析此消息时遇到的未知字段的可变集。如果在.proto文件中指定了option optimize_for = LITE_RUNTIME,则返回类型更改为std::string*。
该类还定义了以下静态方法:
static const Descriptor* Descriptor():返回类型的描述符。这包含关于类型的信息,包括它有哪些字段以及它们的类型。
static const Foo& default_instance():返回Foo的const单例实例,该实例与新建的Foo实例相同。请注意,message的默认实例可以通过调用其New()方法作为工厂使用。
生成的文件名
保留关键字在生成的输出中以下划线追加。
例如,下面的proto3定义语法:
message MyMessage {
string false = 1;
string myFalse = 2;
}
生成以下部分输出:
void clear_false_() ;
const std::string& false_() const;
void set_false_(Arg_&& arg, Args_... args);
std::string* mutable_false_();
PROTOBUF_NODISCARD std::string* release_false_();
void set_allocated_false_(std::string* ptr);
void clear_myfalse() ;
const std::string& myfalse() const;
void set_myfalse(Arg_&& arg, Args_... args);
std::string* mutable_myfalse();
PROTOBUF_NODISCARD std::string* release_myfalse();
void set_allocated_myfalse(std::string* ptr);
嵌套类型
一条消息可以在另一条消息中声明。例如:
message Foo {
message Bar {}
}
在这种情况下,编译器生成两个类:Foo和Foo_Bar。此外,编译器在Foo内部生成一个typedef,如下所示:
typedef Foo_Bar Bar;
这意味着您可以像使用嵌套类Foo::Bar一样使用嵌套类型的类。但是,请注意c++不允许前向声明嵌套类型。如果你想在另一个文件中向前声明Bar并使用该声明,你必须将其标识为Foo_Bar。
字段
除了上一节中描述的方法之外,protocol buffer编译器还为.proto文件中消息中定义的每个字段生成一组访问器方法,比如has_foo()和clear_foo()。
除了访问器方法外,编译器还为每个包含其字段号的字段生成一个整数常量。常量名是字母k,后面跟着转换成驼峰大小写的字段名,后面跟着FieldNumber。例如,给定可选字段int32 foo_bar = 5;,编译器将生成常量static const int kFooBarFieldNumber = 5;
Optional数字字段(proto2和proto3)
对于这两个字段的定义:
optional int32 foo = 1;
required int32 foo = 1;
编译器将生成以下访问器方法:
bool has_foo() const:如果设置了该字段,则返回true。
int32 foo() const:返回字段的当前值。如果未设置该字段,则返回默认值。
void set_foo(int32 value):设置字段的值。调用此函数后,has_foo()将返回true, foo()将返回value。
void clear_foo():清除字段的值。调用此函数后,has_foo()将返回false,而foo()将返回默认值。
对于其他数字字段类型(包括bool), int32将根据标量值类型表替换为相应的c++类型。
Optional String/Bytes字段(proto2和proto3)
对于任何这些字段定义:
optional string foo = 1;
required string foo = 1;
optional bytes foo = 1;
required bytes foo = 1;
编译器将生成以下访问器方法:
bool has_foo() const:如果设置了该字段,则返回true。
const string& foo() const:返回字段的当前值。如果未设置该字段,则返回默认值。
void set_foo(const string& value):设置字段的值。调用此函数后,has_foo()将返回true, foo()将返回value的副本。
void set_foo(string&& value) (c++ 11及以上版本):设置字段的值,从传递的字符串开始移动。调用此函数后,has_foo()将返回true, foo()将返回value的副本。
void set_foo(const char* value):使用c风格的以空结尾的字符串设置字段的值。调用此函数后,has_foo()将返回true, foo()将返回value的副本。
void set_foo(const char* value, int size):和上面一样,但是字符串的大小是显式给出的,而不是通过查找空结束符字节来确定的。
string* mutable_foo():返回一个指向可变字符串对象的指针,该对象存储字段的值。如果在调用之前没有设置该字段,那么返回的字符串将为空(不是默认值)。调用此函数后,has_foo()将返回true,而foo()将返回写入给定字符串的任何值。
void clear_foo():清除字段的值。调用此函数后,has_foo()将返回false,而foo()将返回默认值。
void set_allocated_foo(string* value):将字符串对象设置为字段,如果存在则释放前一个字段的值。如果字符串指针不为NULL,则消息获取分配的字符串对象的所有权,并且has_foo()将返回true。消息可以随时删除分配的字符串对象,因此对该对象的引用可能无效。否则,如果值为NULL,则行为与调用clear_foo()相同。
string* release_foo():释放字段的所有权并返回字符串对象的指针。调用this之后,调用者获得分配的字符串对象的所有权,has_foo()将返回false, foo()将返回默认值。
Optional 枚举字段(proto2、proto3)
给定枚举类型:
enum Bar {
BAR_UNSPECIFIED = 0;
BAR_VALUE = 1;
BAR_OTHER_VALUE = 2;
}
对于这两个字段的定义:
optional Bar foo = 1;
required Bar foo = 1;
编译器将生成以下访问器方法:
bool has_foo() const:如果设置了该字段,则返回true。
Bar foo() const:返回字段的当前值。如果未设置该字段,则返回默认值。
void set_foo(Bar value):设置字段的值。调用此函数后,has_foo()将返回true, foo()将返回value。在调试模式下(即未定义NDEBUG),如果value与为Bar定义的任何值不匹配,则此方法将中止该进程。
void clear_foo():清除字段的值。调用此函数后,has_foo()将返回false,而foo()将返回默认值。
repeated数值字段
对于这个字段的定义:
repeated int32 foo = 1;
int foo_size() const:返回字段中当前元素的数量。要检查空集,请考虑在底层RepeatedField中使用empty()方法,而不是使用此方法。
int32 foo(int index) const:返回给定从零开始的索引处的元素。使用索引不在[0,foo_size())的方法调用此方法会产生未定义的行为。
void set_foo(int index, int32 value):设置元素在给定的从零开始的索引处的值。
void add_foo(int32 value):在给定值的字段末尾添加一个新元素。
void clear_foo():从字段中删除所有元素。调用此函数后,foo_size()将返回0。
const RepeatedField<int32>& foo() const:返回存储字段元素的底层RepeatedField。这个容器类提供了类似stl的迭代器和其他方法。
RepeatedField<int32>* mutable_foo():返回一个指向存储字段元素的底层可变RepeatedField的指针。这个容器类提供了类似stl的迭代器和其他方法。
repeated字符串字段
对于这两个字段的定义:
repeated string foo = 1;
repeated bytes foo = 1;
编译器将生成以下访问器方法:
int foo_size() const:返回字段中当前元素的数量。要检查空集,请考虑在底层RepeatedField中使用empty()方法,而不是使用此方法。
const:返回给定从零开始的索引处的元素。在索引不在[0,foo_size()-1]的情况下调用此方法会产生未定义的行为。
void set_foo(int index, const string& value):设置元素在给定的从零开始的索引处的值。
void set_foo(int index, const char* value):使用c风格的以空结尾的字符串设置给定的从零开始的索引处的元素的值。
void set_foo(int index, const char* value, int size):和上面一样,但是字符串的大小是显式给出的,而不是通过查找空结束符字节来确定的。
string* mutable_foo(int index):返回一个指向可变字符串对象的指针,该对象存储在给定从零开始的索引处的元素的值。使用索引不在[0,foo_size())的方法调用此方法会产生未定义的行为。
void add_foo(const string& value):在给定值的字段末尾添加一个新元素。
void add_foo(const char* value):使用c风格的以空结尾的字符串在字段的末尾追加一个新元素。
void add_foo(const char* value, int size):和上面一样,但是字符串的大小是显式给出的,而不是通过查找空结束符字节来确定的。
string* add_foo():在字段的末尾添加一个新的空字符串元素,并返回一个指向它的指针。
void clear_foo():从字段中删除所有元素。调用此函数后,foo_size()将返回0。
const RepeatedPtrField<string>& foo() const:返回存储字段元素的底层RepeatedPtrField。这个容器类提供了类似stl的迭代器和其他方法。
RepeatedPtrField<string>* mutable_foo():返回一个指向存储字段元素的底层可变 RepeatedPtrField的指针。这个容器类提供了类似stl的迭代器和其他方法。
repeated枚举字段
给定枚举类型:
enum Bar {
BAR_UNSPECIFIED = 0;
BAR_VALUE = 1;
BAR_OTHER_VALUE = 2;
}
对于这个字段的定义:
repeated Bar foo = 1;
编译器将生成以下访问器方法:
int foo_size() const:返回字段中当前元素的数量。要检查空集,请考虑在底层RepeatedField中使用empty()方法,而不是使用此方法。
Bar foo(int index) const:返回给定从零开始的索引处的元素。使用索引不在[0,foo_size())的方法调用此方法会产生未定义的行为。
void set_foo(int index, Bar value):设置元素在给定的从零开始的索引处的值。在调试模式下(即未定义NDEBUG),如果value与为Bar定义的任何值不匹配,则此方法将中止该进程。
void add_foo(Bar value):在给定值的字段末尾添加一个新元素。在调试模式下(即未定义NDEBUG),如果value与为Bar定义的任何值不匹配,则此方法将中止该进程。
void clear_foo():从字段中删除所有元素。调用此函数后,foo_size()将返回0。
const RepeatedField<int>& foo() const:返回存储字段元素的底层RepeatedField。这个容器类提供了类似stl的迭代器和其他方法。
RepeatedField<int>* mutable_foo():返回一个指向存储字段元素的底层可变RepeatedField的指针。这个容器类提供了类似stl的迭代器和其他方法。
repeated嵌入消息字段
给定消息类型:
message Bar {}
对于这个字段的定义:
repeated Bar foo = 1;
编译器将生成以下访问器方法:
int foo_size() const:返回字段中当前元素的数量。要检查空集,请考虑在底层RepeatedField中使用empty()方法,而不是使用此方法。
const Bar& foo(int index) const:返回给定从零开始索引的元素。使用索引不在[0,foo_size())的方法调用此方法会产生未定义的行为。
Bar* mutable_foo(int index):返回一个指向可变Bar对象的指针,该对象存储在给定的从零开始的索引处的元素值。使用索引不在[0,foo_size())的方法调用此方法会产生未定义的行为。
Bar* add_foo():在字段的末尾添加一个新元素并返回一个指向它的指针。返回的Bar是可变的,不会设置任何字段(也就是说,它将与新分配的Bar相同)。
void clear_foo():从字段中删除所有元素。调用此函数后,foo_size()将返回0。
const RepeatedPtrField<Bar>& foo() const:返回存储字段元素的底层RepeatedPtrField。这个容器类提供了类似stl的迭代器和其他方法。
RepeatedPtrField<Bar>* mutable_foo():返回一个指向存储字段元素的底层可变RepeatedPtrField的指针。这个容器类提供了类似stl的迭代器和其他方法。