C++ で生成されたコードのガイド
proto2 と proto3 で生成されたコードの相違点が強調表示されています。これらの相違点は、このドキュメントで説明されている生成されたコードにあり、両方のバージョンで同じ基本メッセージ クラス/インターフェースにはないことに注意してください。このドキュメントを読む前に、proto2 言語ガイドおよび/またはproto3 言語ガイドを読む必要があります。
コンパイラの呼び出し
プロトコル バッファ コンパイラは、--cpp_out=
コマンドライン フラグを指定して呼び出すと、C++ 出力を生成します。--cpp_out=
オプションのパラメータは、コンパイラに C++ 出力を書き込ませたいディレクトリです。コンパイラは、入力の各 .proto
ファイルに対して、ヘッダー ファイルと実装ファイルを作成します。出力ファイルの名前は、.proto
ファイルの名前を取得し、次の 2 つの変更を加えることで計算されます。
- 拡張子 (
.proto
) は、ヘッダー ファイルの場合は.pb.h
、実装ファイルの場合は.pb.cc
に置き換えられます。 - 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
ファイルを読み取り、4 つの出力ファイル (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
は作成しません。これらは既に存在している必要があります。
パッケージ
.proto
ファイルに package
宣言が含まれている場合、ファイルの内容全体が対応する C++ 名前空間に配置されます。たとえば、package
宣言が次のように指定されているとします。
package foo.bar;
ファイル内のすべての宣言は、foo::bar
名前空間に存在します。
メッセージ
単純なメッセージ宣言が与えられた場合
message Foo {}
プロトコル バッファ コンパイラは、google::protobuf::Message
から公開で派生する Foo
という名前のクラスを生成します。このクラスは具象クラスであり、未実装の純粋仮想メソッドは残りません。Message
で仮想であるが純粋仮想ではないメソッドは、最適化モードに応じて、Foo
によってオーバーライドされる場合とされない場合があります。デフォルトでは、Foo
は最大の速度を得るためにすべてのメソッドの特殊化されたバージョンを実装します。ただし、.proto
ファイルに次の行が含まれている場合
option optimize_for = CODE_SIZE;
Foo
は機能に必要な最小限のメソッド セットのみをオーバーライドし、残りのメソッドのリフレクションベースの実装に依存します。これにより、生成されたコードのサイズが大幅に削減されますが、パフォーマンスも低下します。または、.proto
ファイルに次が含まれている場合
option optimize_for = LITE_RUNTIME;
Foo
はすべてのメソッドの高速実装を含みますが、google::protobuf::MessageLite
インターフェースを実装します。このインターフェースには、Message
のメソッドのサブセットのみが含まれています。特に、記述子またはリフレクションはサポートされていません。ただし、このモードでは、生成されたコードは libprotobuf.so
(libprotobuf.lib
) ではなく、libprotobuf-lite.so
(Windows の場合は libprotobuf-lite.lib
) に対してのみリンクする必要があります。「lite」ライブラリは、完全なライブラリよりもはるかに小さく、携帯電話などのリソースが制約されたシステムに適しています。
独自の Foo
サブクラスを作成すべきではありません。このクラスをサブクラス化して仮想メソッドをオーバーライドすると、オーバーライドは無視される可能性があります。多くの生成されたメソッド呼び出しは、パフォーマンスを向上させるために非仮想化されるためです。
Message
インターフェースは、バイナリ文字列との間の解析とシリアライズを含む、メッセージ全体をチェック、操作、読み取り、または書き込みできるメソッドを定義します。
bool ParseFromString(::absl::string_view data)
: 指定されたシリアライズされたバイナリ文字列 (ワイヤー フォーマットとも呼ばれます) からメッセージを解析します。bool SerializeToString(string* output) const
: 指定されたメッセージをバイナリ文字列にシリアライズします。string DebugString()
: proto の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
: このメッセージの解析中に発生した不明なフィールドのセットを返します。option optimize_for = LITE_RUNTIME
が.proto
ファイルで指定されている場合、戻り値の型はstd::string&
に変わります。UnknownFieldSet* mutable_unknown_fields()
: このメッセージの解析中に発生した不明なフィールドの可変セットへのポインタを返します。option optimize_for = LITE_RUNTIME
が.proto
ファイルで指定されている場合、戻り値の型はstd::string*
に変わります。
クラスは、次の静的メソッドも定義します。
static const Descriptor* descriptor()
: 型の記述子を返します。これには、型が持つフィールドとその型を含む、型に関する情報が含まれています。これは、リフレクションでプログラムでフィールドを検査するために使用できます。static const Foo& default_instance()
:Foo
の const シングルトン インスタンスを返します。これは、新しく構築されたFoo
のインスタンスと同一です (したがって、すべての単数フィールドは設定されておらず、すべての繰り返しフィールドは空です)。メッセージのデフォルト インスタンスは、その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
の 2 つのクラスを生成します。さらに、コンパイラは Foo
内に typedef を次のように生成します。
typedef Foo_Bar Bar;
これは、ネストされた型のクラスを、ネストされたクラス Foo::Bar
であるかのように使用できることを意味します。ただし、C++ では、ネストされた型を前方宣言できないことに注意してください。別のファイルで Bar
を前方宣言し、その宣言を使用する場合は、Foo_Bar
として識別する必要があります。
フィールド
前のセクションで説明したメソッドに加えて、プロトコル バッファ コンパイラは、.proto
ファイル内のメッセージ内で定義された各フィールドに対して、アクセサ メソッドのセットを生成します。これらのメソッドは、has_foo()
や clear_foo()
のように、小文字/スネークケースです。
アクセサ メソッドと同様に、コンパイラは各フィールドに対して、そのフィールド番号を含む整数定数を生成します。定数名は、文字 k
、その後にフィールド名をキャメルケースに変換したもの、その後に FieldNumber
が続きます。たとえば、フィールド optional int32 foo_bar = 5;
が与えられた場合、コンパイラは定数 static const int kFooBarFieldNumber = 5;
を生成します。
const
参照を返すフィールド アクセサの場合、その参照は、次の変更アクセスがメッセージに対して行われたときに無効になる可能性があります。これには、任意のフィールドの非 const
アクセサの呼び出し、Message
から継承された非 const
メソッドの呼び出し、または他の方法 (たとえば、メッセージを Swap()
の引数として使用するなど) でメッセージを変更することが含まれます。対応して、返された参照のアドレスは、それまでの間にメッセージに変更アクセスが行われなかった場合にのみ、アクセサの異なる呼び出し間で同じであることが保証されます。
ポインタを返すフィールド アクセサの場合、そのポインタは、次の変更アクセスまたは非変更アクセスがメッセージに対して行われたときに無効になる可能性があります。これには、const 性に関係なく、任意のフィールドのアクセサの呼び出し、Message
から継承された任意のメソッドの呼び出し、または他の方法 (たとえば、コピー コンストラクタを使用してメッセージをコピーするなど) でメッセージにアクセスすることが含まれます。対応して、返されたポインタの値は、アクセサの 2 つの異なる呼び出し間で同じであることが保証されることはありません。
オプションの数値フィールド (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++ 型に置き換えられます。
暗黙的な存在の数値フィールド (proto3)
以下のフィールド定義の場合
int32 foo = 1; // no field label specified, defaults to implicit presence.
コンパイラは、次のアクセサ メソッドを生成します。
int32 foo() const
: フィールドの現在の値を返します。フィールドが設定されていない場合は、0 を返します。void set_foo(int32 value)
: フィールドの値を設定します。これを呼び出した後、foo()
はvalue
を返します。void clear_foo()
: フィールドの値をクリアします。これを呼び出した後、foo()
は 0 を返します。
他の数値フィールド型 (bool
を含む) の場合、スカラー値型テーブルに従って、int32
は対応する C++ 型に置き換えられます。
オプションの String/Bytes フィールド (proto2 および proto3)
注: エディション 2023 以降では、features.(pb.cpp).string_type
が VIEW
に設定されている場合、代わりに string_view API が生成されます。
これらのフィールド定義のいずれかの場合
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(::absl::string_view value)
: フィールドの値を設定します。これを呼び出した後、has_foo()
はtrue
を返し、foo()
はvalue
のコピーを返します。void set_foo(const string& value)
: フィールドの値を設定します。これを呼び出した後、has_foo()
はtrue
を返し、foo()
はvalue
のコピーを返します。void set_foo(string&& value)
: フィールドの値を設定し、渡された文字列から移動します。これを呼び出した後、has_foo()
はtrue
を返し、foo()
はvalue
のコピーを返します。void set_foo(const char* value)
: C スタイルの null 終端文字列を使用してフィールドの値を設定します。これを呼び出した後、has_foo()
はtrue
を返し、foo()
はvalue
のコピーを返します。void set_foo(const char* value, int size)
: null 終端バイトを探して決定するのではなく、明示的にサイズが指定された文字列を使用してフィールドの値を設定します。これを呼び出した後、has_foo()
はtrue
を返し、foo()
はvalue
のコピーを返します。string* mutable_foo()
: フィールドの値を格納する可変string
オブジェクトへのポインタを返します。呼び出し前にフィールドが設定されていなかった場合、返される文字列は空になります (デフォルト値ではありません)。これを呼び出した後、has_foo()
はtrue
を返し、foo()
は指定された文字列に書き込まれた値を返します。void clear_foo()
: フィールドの値をクリアします。これを呼び出した後、has_foo()
はfalse
を返し、foo()
はデフォルト値を返します。void set_allocated_foo(string* value)
:string
オブジェクトをフィールドに設定し、以前のフィールド値が存在する場合は解放します。string
ポインタがNULL
でない場合、メッセージは割り当てられたstring
オブジェクトの所有権を取得し、has_foo()
はtrue
を返します。メッセージはいつでも割り当てられたstring
オブジェクトを削除できるため、オブジェクトへの参照は無効になる可能性があります。それ以外の場合、value
がNULL
の場合、動作はclear_foo()
を呼び出す場合と同じです。string* release_foo()
: フィールドの所有権を解放し、string
オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられたstring
オブジェクトの所有権を取得し、has_foo()
はfalse
を返し、foo()
はデフォルト値を返します。
暗黙的な存在の String/Bytes フィールド (proto3)
注: エディション 2023 以降では、features.(pb.cpp).string_type
が VIEW
に設定されている場合、代わりに string_view API が生成されます。
これらのフィールド定義のいずれか
string foo = 1; // no field label specified, defaults to implicit presence.
bytes foo = 1;
コンパイラは、次のアクセサ メソッドを生成します。
const string& foo() const
: フィールドの現在の値を返します。フィールドが設定されていない場合は、空の文字列/空のバイトを返します。void set_foo(::absl::string_view value)
: フィールドの値を設定します。これを呼び出した後、foo()
はvalue
のコピーを返します。void set_foo(const string& value)
: フィールドの値を設定します。これを呼び出した後、foo()
はvalue
のコピーを返します。void set_foo(string&& value)
: フィールドの値を設定し、渡された文字列から移動します。これを呼び出した後、foo()
はvalue
のコピーを返します。void set_foo(const char* value)
: C スタイルの null 終端文字列を使用してフィールドの値を設定します。これを呼び出した後、foo()
はvalue
のコピーを返します。void set_foo(const char* value, int size)
: null 終端バイトを探して決定するのではなく、明示的にサイズが指定された文字列を使用してフィールドの値を設定します。これを呼び出した後、foo()
はvalue
のコピーを返します。string* mutable_foo()
: フィールドの値を格納する可変string
オブジェクトへのポインタを返します。呼び出し前にフィールドが設定されていなかった場合、返される文字列は空になります。これを呼び出した後、foo()
は指定された文字列に書き込まれた値を返します。void clear_foo()
: フィールドの値をクリアします。これを呼び出した後、foo()
は空の文字列/空のバイトを返します。void set_allocated_foo(string* value)
:string
オブジェクトをフィールドに設定し、以前のフィールド値が存在する場合は解放します。string
ポインタがNULL
でない場合、メッセージは割り当てられたstring
オブジェクトの所有権を取得します。メッセージはいつでも割り当てられたstring
オブジェクトを削除できるため、オブジェクトへの参照は無効になる可能性があります。それ以外の場合、value
がNULL
の場合、動作はclear_foo()
を呼び出す場合と同じです。string* release_foo()
: フィールドの所有権を解放し、string
オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられたstring
オブジェクトの所有権を取得し、foo()
は空の文字列/空のバイトを返します。
Cord サポート付きの単数 Bytes フィールド
v23.0 では、単数 bytes
フィールド (oneof
フィールドを含む) の absl::Cord
のサポートが追加されました。単数 string
、repeated string
、および repeated bytes
フィールドは、Cord
の使用をサポートしていません。
単数 bytes
フィールドを absl::Cord
を使用してデータを格納するように設定するには、次の構文を使用します。
optional bytes foo = 25 [ctype=CORD];
bytes bar = 26 [ctype=CORD];
cord
の使用は、repeated bytes
フィールドでは使用できません。Protoc は、これらのフィールドの [ctype=CORD]
設定を無視します。
コンパイラは、次のアクセサ メソッドを生成します。
const ::absl::Cord& foo() const
: フィールドの現在の値を返します。フィールドが設定されていない場合は、空のCord
(proto3) またはデフォルト値 (proto2) を返します。void set_foo(const ::absl::Cord& value)
: フィールドの値を設定します。これを呼び出した後、foo()
はvalue
を返します。void set_foo(::absl::string_view value)
: フィールドの値を設定します。これを呼び出した後、foo()
はabsl::Cord
としてvalue
を返します。void clear_foo()
: フィールドの値をクリアします。これを呼び出した後、foo()
は空のCord
(proto3) またはデフォルト値 (proto2) を返します。bool has_foo()
: フィールドが設定されている場合はtrue
を返します。
オプションの Enum フィールド (proto2 および proto3)
enum 型が与えられた場合
enum Bar {
BAR_UNSPECIFIED = 0;
BAR_VALUE = 1;
BAR_OTHER_VALUE = 2;
}
これらのフィールド定義のいずれか
optional Bar bar = 1;
required Bar bar = 1;
コンパイラは、次のアクセサ メソッドを生成します。
bool has_bar() const
: フィールドが設定されている場合はtrue
を返します。Bar bar() const
: フィールドの現在の値を返します。フィールドが設定されていない場合は、デフォルト値を返します。void set_bar(Bar value)
: フィールドの値を設定します。これを呼び出した後、has_bar()
はtrue
を返し、bar()
はvalue
を返します。デバッグ モード (つまり、NDEBUG が定義されていない場合) では、value
がBar
に定義された値のいずれとも一致しない場合、このメソッドはプロセスを中止します。void clear_bar()
: フィールドの値をクリアします。これを呼び出した後、has_bar()
はfalse
を返し、bar()
はデフォルト値を返します。
暗黙的な存在の Enum フィールド (proto3)
enum 型が与えられた場合
enum Bar {
BAR_UNSPECIFIED = 0;
BAR_VALUE = 1;
BAR_OTHER_VALUE = 2;
}
このフィールド定義の場合
Bar bar = 1; // no field label specified, defaults to implicit presence.
コンパイラは、次のアクセサ メソッドを生成します。
Bar bar() const
: フィールドの現在の値を返します。フィールドが設定されていない場合は、デフォルト値 (0) を返します。void set_bar(Bar value)
: フィールドの値を設定します。これを呼び出した後、bar()
はvalue
を返します。void clear_bar()
: フィールドの値をクリアします。これを呼び出した後、bar()
はデフォルト値を返します。
オプションの埋め込みメッセージ フィールド (proto2 および proto3)
メッセージ型が与えられた場合
message Bar {}
これらのフィールド定義のいずれかの場合
//proto2
optional Bar bar = 1;
required Bar bar = 1;
//proto3
Bar bar = 1;
コンパイラは、次のアクセサ メソッドを生成します。
bool has_bar() const
: フィールドが設定されている場合はtrue
を返します。const Bar& bar() const
: フィールドの現在の値を返します。フィールドが設定されていない場合は、フィールドが設定されていないBar
(おそらくBar::default_instance()
) を返します。Bar* mutable_bar()
: フィールドの値を格納する可変Bar
オブジェクトへのポインタを返します。呼び出し前にフィールドが設定されていなかった場合、返されるBar
にはフィールドが設定されていません (つまり、新しく割り当てられたBar
と同一になります)。これを呼び出した後、has_bar()
はtrue
を返し、bar()
はBar
の同じインスタンスへの参照を返します。void clear_bar()
: フィールドの値をクリアします。これを呼び出した後、has_bar()
はfalse
を返し、bar()
はデフォルト値を返します。void set_allocated_bar(Bar* bar)
:Bar
オブジェクトをフィールドに設定し、以前のフィールド値が存在する場合は解放します。Bar
ポインタがNULL
でない場合、メッセージは割り当てられたBar
オブジェクトの所有権を取得し、has_bar()
はtrue
を返します。それ以外の場合、Bar
がNULL
の場合、動作はclear_bar()
を呼び出す場合と同じです。Bar* release_bar()
: フィールドの所有権を解放し、Bar
オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられたBar
オブジェクトの所有権を取得し、has_bar()
はfalse
を返し、bar()
はデフォルト値を返します。
繰り返し数値フィールド
このフィールド定義の場合
repeated int32 foo = 1;
コンパイラは、次のアクセサ メソッドを生成します。
int foo_size() const
: フィールドに現在存在する要素の数を返します。空のセットを確認するには、このメソッドの代わりに、基になるRepeatedField
のempty()
メソッドの使用を検討してください。int32 foo(int index) const
: 指定された 0 から始まるインデックスにある要素を返します。このメソッドを [0, foo_size()) の範囲外のインデックスで呼び出すと、未定義の動作になります。void set_foo(int index, int32 value)
: 指定された 0 から始まるインデックスにある要素の値を設定します。void add_foo(int32 value)
: 指定された値を持つ新しい要素をフィールドの最後に追加します。void clear_foo()
: フィールドからすべての要素を削除します。これを呼び出した後、foo_size()
はゼロを返します。const RepeatedField<int32>& foo() const
: フィールドの要素を格納する基になるRepeatedField
を返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。RepeatedField<int32>* mutable_foo()
: フィールドの要素を格納する基になる可変RepeatedField
へのポインタを返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。
他の数値フィールド型 (bool
を含む) の場合、スカラー値型テーブルに従って、int32
は対応する C++ 型に置き換えられます。
繰り返し String フィールド
注: エディション 2023 以降では、features.(pb.cpp).string_type
が VIEW
に設定されている場合、代わりに string_view API が生成されます。
これらのフィールド定義のいずれか
repeated string foo = 1;
repeated bytes foo = 1;
コンパイラは、次のアクセサ メソッドを生成します。
int foo_size() const
: フィールドに現在存在する要素の数を返します。空のセットを確認するには、このメソッドの代わりに、基になるRepeatedField
のempty()
メソッドの使用を検討してください。const string& foo(int index) const
: 指定された 0 から始まるインデックスにある要素を返します。このメソッドを [0, foo_size()-1] の範囲外のインデックスで呼び出すと、未定義の動作になります。void set_foo(int index, ::absl::string_view value)
: 指定された 0 から始まるインデックスにある要素の値を設定します。void set_foo(int index, const string& value)
: 指定された 0 から始まるインデックスにある要素の値を設定します。void set_foo(int index, string&& value)
: 指定された 0 から始まるインデックスにある要素の値を設定し、渡された文字列から移動します。void set_foo(int index, const char* value)
: C スタイルの null 終端文字列を使用して、指定された 0 から始まるインデックスにある要素の値を設定します。void set_foo(int index, const char* value, int size)
: null 終端バイトを探して決定するのではなく、明示的にサイズが指定された C スタイルの文字列を使用して、指定された 0 から始まるインデックスにある要素の値を設定します。string* mutable_foo(int index)
: 指定された 0 から始まるインデックスにある要素の値を格納する可変string
オブジェクトへのポインタを返します。このメソッドを [0, foo_size()) の範囲外のインデックスで呼び出すと、未定義の動作になります。void add_foo(::absl::string_view value)
: 指定された 0 から始まるインデックスにある要素の最後尾に新しい要素を追加します。void add_foo(const string& value)
: 指定された値を持つ新しい要素をフィールドの最後に追加します。void add_foo(string&& value)
: フィールドの最後尾に新しい要素を追加し、渡された文字列から移動します。void add_foo(const char* value)
: C スタイルの null 終端文字列を使用して、フィールドの最後尾に新しい要素を追加します。void add_foo(const char* value, int size)
: null 終端バイトを探して決定するのではなく、明示的にサイズが指定された文字列を使用して、フィールドの最後尾に新しい要素を追加します。string* add_foo()
: フィールドの最後尾に新しい空の文字列要素を追加し、そのポインタを返します。void clear_foo()
: フィールドからすべての要素を削除します。これを呼び出した後、foo_size()
はゼロを返します。const RepeatedPtrField<string>& foo() const
: フィールドの要素を格納する基になるRepeatedPtrField
を返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。RepeatedPtrField<string>* mutable_foo()
: フィールドの要素を格納する基になる可変RepeatedPtrField
へのポインタを返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。
繰り返し Enum フィールド
enum 型が与えられた場合
enum Bar {
BAR_UNSPECIFIED = 0;
BAR_VALUE = 1;
BAR_OTHER_VALUE = 2;
}
このフィールド定義の場合
repeated Bar bar = 1;
コンパイラは、次のアクセサ メソッドを生成します。
int bar_size() const
: フィールドに現在存在する要素の数を返します。空のセットを確認するには、このメソッドの代わりに、基になるRepeatedField
のempty()
メソッドの使用を検討してください。Bar bar(int index) const
: 指定された 0 から始まるインデックスにある要素を返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作になります。void set_bar(int index, Bar value)
: 指定された 0 から始まるインデックスにある要素の値を設定します。デバッグ モード (つまり、NDEBUG が定義されていない場合) では、value
がBar
に定義された値のいずれとも一致しない場合、このメソッドはプロセスを中止します。void add_bar(Bar value)
: 指定された値を持つ新しい要素をフィールドの最後に追加します。デバッグ モード (つまり、NDEBUG が定義されていない場合) では、value
がBar
に定義された値のいずれとも一致しない場合、このメソッドはプロセスを中止します。void clear_bar()
: フィールドからすべての要素を削除します。これを呼び出した後、bar_size()
はゼロを返します。const RepeatedField<int>& bar() const
: フィールドの要素を格納する基になるRepeatedField
を返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。RepeatedField<int>* mutable_bar()
: フィールドの要素を格納する基になる可変RepeatedField
へのポインタを返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。
繰り返し埋め込みメッセージ フィールド
メッセージ型が与えられた場合
message Bar {}
このフィールド定義の場合
repeated Bar bar = 1;
コンパイラは、次のアクセサ メソッドを生成します。
int bar_size() const
: フィールドに現在存在する要素の数を返します。空のセットを確認するには、このメソッドの代わりに、基になるRepeatedField
のempty()
メソッドの使用を検討してください。const Bar& bar(int index) const
: 指定された 0 から始まるインデックスにある要素を返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作になります。Bar* mutable_bar(int index)
: 指定された 0 から始まるインデックスにある要素の値を格納する可変Bar
オブジェクトへのポインタを返します。このメソッドを [0, bar_size()) の範囲外のインデックスで呼び出すと、未定義の動作になります。Bar* add_bar()
: フィールドの最後尾に新しい要素を追加し、そのポインタを返します。返されるBar
は可変であり、フィールドは設定されていません (つまり、新しく割り当てられたBar
と同一になります)。void clear_bar()
: フィールドからすべての要素を削除します。これを呼び出した後、bar_size()
はゼロを返します。const RepeatedPtrField<Bar>& bar() const
: フィールドの要素を格納する基になるRepeatedPtrField
を返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。RepeatedPtrField<Bar>* mutable_bar()
: フィールドの要素を格納する基になる可変RepeatedPtrField
へのポインタを返します。このコンテナ クラスは、STL のようなイテレータやその他のメソッドを提供します。
Oneof 数値フィールド
この oneof フィールド定義の場合
oneof example_name {
int32 foo = 1;
...
}
コンパイラは、次のアクセサ メソッドを生成します。
bool has_foo() const
: oneof ケースがkFoo
の場合はtrue
を返します。int32 foo() const
: oneof ケースがkFoo
の場合はフィールドの現在の値を返します。それ以外の場合は、デフォルト値を返します。void set_foo(int32 value)
:- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
clear_example_name()
を呼び出します。 - このフィールドの値を設定し、oneof case を
kFoo
に設定します。 has_foo()
は true を返し、foo()
はvalue
を返し、example_name_case()
はkFoo
を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
void clear_foo()
:- oneof case が
kFoo
でない場合、何も変更されません。 - oneof case が
kFoo
の場合、フィールドの値と oneof case をクリアします。has_foo()
はfalse
を返し、foo()
はデフォルト値を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。
- oneof case が
他の数値型フィールド(bool
を含む)の場合、int32
は スカラー値型テーブル に従って対応する C++ 型に置き換えられます。
Oneof String フィールド
注: 2023 年版以降、string_view API が代わりに生成される場合があります。
これらの oneof フィールド定義のいずれかについて
oneof example_name {
string foo = 1;
...
}
oneof example_name {
bytes foo = 1;
...
}
コンパイラは、次のアクセサ メソッドを生成します。
bool has_foo() const
: oneof case がkFoo
の場合にtrue
を返します。const string& foo() const
: oneof case がkFoo
の場合、フィールドの現在の値を返します。それ以外の場合は、デフォルト値を返します。void set_foo(::absl::string_view value)
:- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
clear_example_name()
を呼び出します。 - このフィールドの値を設定し、oneof case を
kFoo
に設定します。 has_foo()
はtrue
を返し、foo()
はvalue
のコピーを返し、example_name_case()
はkFoo
を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
void set_foo(const string& value)
: 最初のset_foo()
と同様ですが、const string 参照からコピーします。void set_foo(string&& value)
: 最初のset_foo()
と同様ですが、渡された文字列からムーブします。void set_foo(const char* value)
: 最初のset_foo()
と同様ですが、C スタイルのヌル終端文字列からコピーします。void set_foo(const char* value, int size)
: 最初のset_foo()
と同様ですが、ヌル終端バイトを探すのではなく、明示的に指定されたサイズを持つ文字列からコピーします。string* mutable_foo()
:- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
clear_example_name()
を呼び出します。 - oneof case を
kFoo
に設定し、フィールドの値を格納するミュータブルな string オブジェクトへのポインタを返します。呼び出し前に oneof case がkFoo
でなかった場合、返される文字列は空になります(デフォルト値ではありません)。 has_foo()
はtrue
を返し、foo()
は与えられた文字列に書き込まれた値を返し、example_name_case()
はkFoo
を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
void clear_foo()
:- oneof case が
kFoo
でない場合、何も変更されません。 - oneof case が
kFoo
の場合、フィールドを解放し、oneof case をクリアします。has_foo()
はfalse
を返し、foo()
はデフォルト値を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。
- oneof case が
void set_allocated_foo(string* value)
:clear_example_name()
を呼び出します。- string ポインタが
NULL
でない場合: string オブジェクトをフィールドに設定し、oneof case をkFoo
に設定します。メッセージは割り当てられた string オブジェクトの所有権を取得し、has_foo()
はtrue
を返し、example_name_case()
はkFoo
を返します。 - string ポインタが
NULL
の場合、has_foo()
はfalse
を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。
string* release_foo()
:- oneof case が
kFoo
でない場合、NULL
を返します。 - oneof case をクリアし、フィールドの所有権を解放し、string オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられた string オブジェクトの所有権を取得し、
has_foo()
は false を返し、foo()
はデフォルト値を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。
- oneof case が
Oneof Enum フィールド
enum 型が与えられた場合
enum Bar {
BAR_UNSPECIFIED = 0;
BAR_VALUE = 1;
BAR_OTHER_VALUE = 2;
}
oneof フィールド定義の場合
oneof example_name {
Bar bar = 1;
...
}
コンパイラは、次のアクセサ メソッドを生成します。
bool has_bar() const
: oneof case がkBar
の場合にtrue
を返します。Bar bar() const
: oneof case がkBar
の場合、フィールドの現在の値を返します。それ以外の場合は、デフォルト値を返します。void set_bar(Bar value)
:- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
clear_example_name()
を呼び出します。 - このフィールドの値を設定し、oneof case を
kBar
に設定します。 has_bar()
はtrue
を返し、bar()
はvalue
を返し、example_name_case()
はkBar
を返します。- デバッグモード(つまり、NDEBUG が定義されていない場合)で、
value
がBar
に定義された値のいずれにも一致しない場合、このメソッドはプロセスを中止します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
void clear_bar()
:- oneof case が
kBar
でない場合、何も変更されません。 - oneof case が
kBar
の場合、フィールドの値と oneof case をクリアします。has_bar()
はfalse
を返し、bar()
はデフォルト値を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。
- oneof case が
Oneof 埋め込みメッセージ フィールド
メッセージ型が与えられた場合
message Bar {}
oneof フィールド定義の場合
oneof example_name {
Bar bar = 1;
...
}
コンパイラは、次のアクセサ メソッドを生成します。
bool has_bar() const
: oneof case がkBar
の場合に true を返します。const Bar& bar() const
: oneof case がkBar
の場合、フィールドの現在の値を返します。それ以外の場合は、フィールドが設定されていない Bar(おそらくBar::default_instance()
)を返します。Bar* mutable_bar()
:- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
clear_example_name()
を呼び出します。 - oneof case を
kBar
に設定し、フィールドの値を格納するミュータブルな Bar オブジェクトへのポインタを返します。呼び出し前に oneof case がkBar
でなかった場合、返される Bar はフィールドが設定されていません(つまり、新しく割り当てられた Bar と同じになります)。 - これを呼び出した後、
has_bar()
はtrue
を返し、bar()
はBar
の同じインスタンスへの参照を返し、example_name_case()
はkBar
を返します。
- 同じ oneof 内の他の oneof フィールドが設定されている場合は、
void clear_bar()
:- oneof case が
kBar
でない場合、何も変更されません。 - oneof case が
kBar
と等しい場合、フィールドを解放し、oneof case をクリアします。has_bar()
はfalse
を返し、bar()
はデフォルト値を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。
- oneof case が
void set_allocated_bar(Bar* bar)
:clear_example_name()
を呼び出します。Bar
ポインタがNULL
でない場合:Bar
オブジェクトをフィールドに設定し、oneof case をkBar
に設定します。メッセージは割り当てられたBar
オブジェクトの所有権を取得し、has_bar() は true を返し、example_name_case()
はkBar
を返します。- ポインタが
NULL
の場合、has_bar()
はfalse
を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。(動作はclear_example_name()
の呼び出しに似ています)
Bar* release_bar()
:- oneof case が
kBar
でない場合、NULL
を返します。 - oneof case が
kBar
の場合、oneof case をクリアし、フィールドの所有権を解放し、Bar
オブジェクトのポインタを返します。これを呼び出した後、呼び出し元は割り当てられたBar
オブジェクトの所有権を取得し、has_bar()
はfalse
を返し、bar()
はデフォルト値を返し、example_name_case()
はEXAMPLE_NAME_NOT_SET
を返します。
- oneof case が
Map フィールド
この map フィールド定義の場合
map<int32, int32> weight = 1;
コンパイラは、次のアクセサ メソッドを生成します。
const google::protobuf::Map<int32, int32>& weight();
: イミュータブルなMap
を返します。google::protobuf::Map<int32, int32>* mutable_weight();
: ミュータブルなMap
を返します。
google::protobuf::Map
は、プロトコルバッファで map フィールドを格納するために使用される特別なコンテナ型です。以下のインターフェースからわかるように、std::map
および std::unordered_map
メソッドの一般的に使用されるサブセットを使用しています。
注
これらの map は順序付けられていません。template<typename Key, typename T> {
class Map {
// Member types
typedef Key key_type;
typedef T mapped_type;
typedef MapPair< Key, T > value_type;
// Iterators
iterator begin();
const_iterator begin() const;
const_iterator cbegin() const;
iterator end();
const_iterator end() const;
const_iterator cend() const;
// Capacity
int size() const;
bool empty() const;
// Element access
T& operator[](const Key& key);
const T& at(const Key& key) const;
T& at(const Key& key);
// Lookup
bool contains(const Key& key) const;
int count(const Key& key) const;
const_iterator find(const Key& key) const;
iterator find(const Key& key);
// Modifiers
pair<iterator, bool> insert(const value_type& value);
template<class InputIt>
void insert(InputIt first, InputIt last);
size_type erase(const Key& Key);
iterator erase(const_iterator pos);
iterator erase(const_iterator first, const_iterator last);
void clear();
// Copy
Map(const Map& other);
Map& operator=(const Map& other);
}
データを追加する最も簡単な方法は、通常の map 構文を使用することです。たとえば
std::unique_ptr<ProtoName> my_enclosing_proto(new ProtoName);
(*my_enclosing_proto->mutable_weight())[my_key] = my_value;
pair<iterator, bool> insert(const value_type& value)
は、value_type
インスタンスのディープコピーを暗黙的に引き起こします。google::protobuf::Map
に新しい値を挿入する最も効率的な方法は、次のとおりです
T& operator[](const Key& key): map[new_key] = new_mapped;
標準 map での google::protobuf::Map
の使用
google::protobuf::Map
は、std::map
および std::unordered_map
と同じイテレータ API をサポートしています。google::protobuf::Map
を直接使用したくない場合は、次のようにして google::protobuf::Map
を標準 map に変換できます
std::map<int32, int32> standard_map(message.weight().begin(),
message.weight().end());
これにより、map 全体のディープコピーが作成されることに注意してください。
次のようにして、標準 map から google::protobuf::Map
を構築することもできます
google::protobuf::Map<int32, int32> weight(standard_map.begin(), standard_map.end());
不明な値の解析
ワイヤ上では、.proto map はキー/値ペアごとに map エントリメッセージと同等ですが、map 自体は map エントリの繰り返しフィールドです。通常のメッセージ型と同様に、解析された map エントリメッセージに不明なフィールドが含まれている可能性があります。たとえば、map<int32, string>
として定義された map 内の int64
型のフィールドなどです。
map エントリメッセージのワイヤ形式に不明なフィールドがある場合、それらは破棄されます。
map エントリメッセージのワイヤ形式に不明な enum 値がある場合、proto2 と proto3 で処理が異なります。proto2 では、map エントリメッセージ全体が、包含メッセージの不明なフィールドセットに入れられます。proto3 では、既知の enum 値であるかのように map フィールドに入れられます。
Any
次のような Any
フィールドが与えられた場合
import "google/protobuf/any.proto";
message ErrorStatus {
string message = 1;
google.protobuf.Any details = 2;
}
生成されたコードでは、details
フィールドのゲッターは google::protobuf::Any
のインスタンスを返します。これにより、Any
の値をパックおよびアンパックするための次の特別なメソッドが提供されます
class Any {
public:
// Packs the given message into this Any using the default type URL
// prefix “type.googleapis.com”. Returns false if serializing the message failed.
bool PackFrom(const google::protobuf::Message& message);
// Packs the given message into this Any using the given type URL
// prefix. Returns false if serializing the message failed.
bool PackFrom(const google::protobuf::Message& message,
::absl::string_view type_url_prefix);
// Unpacks this Any to a Message. Returns false if this Any
// represents a different protobuf type or parsing fails.
bool UnpackTo(google::protobuf::Message* message) const;
// Returns true if this Any represents the given protobuf type.
template<typename T> bool Is() const;
}
Oneof
次のような oneof 定義が与えられた場合
oneof example_name {
int32 foo_int = 4;
string foo_string = 9;
...
}
コンパイラは、次の C++ enum 型を生成します
enum ExampleNameCase {
kFooInt = 4,
kFooString = 9,
EXAMPLE_NAME_NOT_SET = 0
}
さらに、次のメソッドを生成します
ExampleNameCase example_name_case() const
: どのフィールドが設定されているかを示す enum を返します。どれも設定されていない場合はEXAMPLE_NAME_NOT_SET
を返します。void clear_example_name()
: oneof フィールドセットがポインタ(Message または String)を使用している場合、オブジェクトを解放し、oneof case をEXAMPLE_NAME_NOT_SET
に設定します。
列挙型
注: 2024 年版以降、特定の機能設定で string_view
API が生成される場合があります。このトピックの詳細については、列挙型名ヘルパー を参照してください。
次のような enum 定義が与えられた場合
enum Foo {
VALUE_A = 0;
VALUE_B = 5;
VALUE_C = 1234;
}
プロトコルバッファコンパイラは、同じ値セットを持つ Foo
という名前の C++ enum 型を生成します。さらに、コンパイラは次の関数を生成します
const EnumDescriptor* Foo_descriptor()
: この enum 型が定義する値に関する情報を含む、型の記述子を返します。bool Foo_IsValid(int value)
: 指定された数値がFoo
の定義済み値のいずれかに一致する場合、true
を返します。上記の例では、入力が 0、5、または 1234 の場合にtrue
を返します。const string& Foo_Name(int value)
: 指定された数値の名前を返します。そのような値が存在しない場合は、空の文字列を返します。複数の値がこの数値を持つ場合、最初に定義された値が返されます。上記の例では、Foo_Name(5)
は"VALUE_B"
を返します。bool Foo_Parse(::absl::string_view name, Foo* value)
:name
がこの enum の有効な値名である場合、その値をvalue
に代入し、true を返します。それ以外の場合は false を返します。上記の例では、Foo_Parse("VALUE_C", &some_foo)
は true を返し、some_foo
を 1234 に設定します。const Foo Foo_MIN
: enum の最小有効値(例では VALUE_A)。const Foo Foo_MAX
: enum の最大有効値(例では VALUE_C)。const int Foo_ARRAYSIZE
: 常にFoo_MAX + 1
として定義されます。
整数を proto2 enum にキャストする場合は注意してください。整数が proto2 enum 値にキャストされる場合、整数は、その enum の有効な値のいずれかでなければなりません。そうでない場合、結果は未定義になる可能性があります。疑問がある場合は、生成された Foo_IsValid()
関数を使用して、キャストが有効かどうかをテストしてください。proto2 メッセージの enum 型フィールドを無効な値に設定すると、アサーションエラーが発生する可能性があります。proto2 メッセージの解析時に無効な enum 値が読み取られると、不明なフィールド として扱われます。これらのセマンティクスは proto3 で変更されました。int32 に収まる限り、任意の整数を proto3 enum 値にキャストしても安全です。proto3 メッセージの解析時に無効な enum 値も保持され、enum フィールドアクセサーによって返されます。
switch ステートメントで proto3 enum を使用する場合は注意してください。Proto3 enum は、指定されたシンボルの範囲外の可能な値を持つオープン enum 型です。認識されない enum 値は、proto3 メッセージの解析時に保持され、enum フィールドアクセサーによって返されます。既知のフィールドがすべてリストされている場合でも、デフォルトケースのない proto3 enum の switch ステートメントは、すべてのケースをキャッチできるとは限りません。これにより、データの破損やランタイムクラッシュなどの予期しない動作が発生する可能性があります。常にデフォルトケースを追加するか、switch の外部で明示的に Foo_IsValid(int)
を呼び出して、不明な enum 値を処理してください。
メッセージ型内で enum を定義できます。この場合、プロトコルバッファコンパイラは、enum 型自体がメッセージのクラス内にネストされて宣言されているように見えるコードを生成します。Foo_descriptor()
関数と Foo_IsValid()
関数は、静的メソッドとして宣言されます。実際には、enum 型自体とその値は、マングルされた名前でグローバルスコープで宣言され、typedef と一連の定数定義を使用してクラスのスコープにインポートされます。これは、宣言順序に関する問題を回避するためだけに行われます。マングルされたトップレベルの名前には依存しないでください。enum が実際にメッセージクラスにネストされていると見なしてください。
拡張機能 (proto2 のみ)
拡張範囲を持つメッセージが与えられた場合
message Foo {
extensions 100 to 199;
}
プロトコルバッファコンパイラは、Foo
用に追加のメソッドを生成します。HasExtension()
、ExtensionSize()
、ClearExtension()
、GetExtension()
、SetExtension()
、MutableExtension()
、AddExtension()
、SetAllocatedExtension()
、ReleaseExtension()
です。これらの各メソッドは、最初のパラメータとして、拡張フィールドを識別する拡張識別子(下記で説明)を取ります。残りのパラメータと戻り値は、拡張識別子と同じ型の通常の(非拡張)フィールドに対して生成されるアクセスメソッドに対応するものとまったく同じです。(GetExtension()
は、特別なプレフィックスのないアクセサーに対応します。)
拡張定義が与えられた場合
extend Foo {
optional int32 bar = 123;
repeated int32 repeated_bar = 124;
optional Bar message_bar = 125;
}
単数拡張フィールド bar
の場合、プロトコルバッファコンパイラは、この拡張機能にアクセスするために Foo
の拡張アクセサーで使用できる bar
という名前の「拡張識別子」を生成します。次に例を示します
Foo foo;
assert(!foo.HasExtension(bar));
foo.SetExtension(bar, 1);
assert(foo.HasExtension(bar));
assert(foo.GetExtension(bar) == 1);
foo.ClearExtension(bar);
assert(!foo.HasExtension(bar));
メッセージ拡張フィールド message_bar
の場合、フィールドが設定されていない場合、foo.GetExtension(message_bar)
は、フィールドが設定されていない Bar
(おそらく Bar::default_instance()
)を返します。
同様に、繰り返し拡張フィールド repeated_bar
の場合、コンパイラは repeated_bar
という名前の拡張識別子を生成します。これも Foo
の拡張アクセサーで使用できます
Foo foo;
for (int i = 0; i < kSize; ++i) {
foo.AddExtension(repeated_bar, i)
}
assert(foo.ExtensionSize(repeated_bar) == kSize)
for (int i = 0; i < kSize; ++i) {
assert(foo.GetExtension(repeated_bar, i) == i)
}
(拡張識別子の正確な実装は複雑で、テンプレートの魔法のような使用が含まれますが、拡張識別子を使用するためにその仕組みについて心配する必要はありません。)
拡張機能は、別の型の中にネストして宣言できます。たとえば、一般的なパターンは、次のようなことを行うことです
message Baz {
extend Foo {
optional Baz foo_ext = 124;
}
}
この場合、拡張識別子 foo_ext
は Baz
の内部にネストして宣言されます。次のように使用できます
Foo foo;
Baz* baz = foo.MutableExtension(Baz::foo_ext);
FillInMyBaz(baz);
Arena アロケーション
アリーナ割り当ては、プロトコルバッファを扱う際のメモリ使用量を最適化し、パフォーマンスを向上させるのに役立つ C++ のみの機能です。.proto
でアリーナ割り当てを有効にすると、アリーナを扱うための追加コードが C++ 生成コードに追加されます。アリーナ割り当て API の詳細については、アリーナ割り当てガイド を参照してください。
サービス
.proto
ファイルに次の行が含まれている場合
option cc_generic_services = true;
次に、プロトコルバッファコンパイラは、このセクションで説明されているように、ファイルで見つかったサービス定義に基づいてコードを生成します。ただし、生成されたコードは、特定の RPC システムに関連付けられていないため、望ましくない場合があります。したがって、1 つのシステムに合わせたコードよりも多くのレベルの間接参照が必要です。このコードを生成したくない場合は、次の行をファイルに追加します
option cc_generic_services = false;
上記の行のいずれも指定されていない場合、オプションはデフォルトで false
になります。これは、汎用サービスが非推奨になったためです。(2.4.0 より前のバージョンでは、オプションはデフォルトで true
であったことに注意してください)
.proto
言語サービス定義に基づく RPC システムは、システムに適したコードを生成するための プラグイン を提供する必要があります。これらのプラグインは、抽象サービスを無効にして、同じ名前の独自のクラスを生成できるようにする必要がある可能性があります。
このセクションの残りの部分では、抽象サービスが有効になっている場合にプロトコルバッファコンパイラが生成する内容について説明します。
インターフェース
サービス定義が与えられた場合
service Foo {
rpc Bar(FooRequest) returns(FooResponse);
}
プロトコルバッファコンパイラは、このサービスを表すクラス Foo
を生成します。Foo
には、サービス定義で定義された各メソッドの仮想メソッドがあります。この場合、メソッド Bar
は次のように定義されています
virtual void Bar(RpcController* controller, const FooRequest* request,
FooResponse* response, Closure* done);
パラメータは、method
引数が暗黙的であり、request
および response
が正確な型を指定することを除いて、Service::CallMethod()
のパラメータと同等です。
これらの生成されたメソッドは仮想ですが、純粋仮想ではありません。デフォルトの実装は、メソッドが実装されていないことを示すエラーメッセージで controller->SetFailed()
を呼び出し、次に done
コールバックを呼び出すだけです。独自のサービスを実装する場合は、この生成されたサービスをサブクラス化し、そのメソッドを適切に実装する必要があります。
Foo
は Service
インターフェースをサブクラス化します。プロトコルバッファコンパイラは、次のように Service
のメソッドの実装を自動的に生成します
GetDescriptor
: サービスのServiceDescriptor
を返します。CallMethod
: 提供されたメソッド記述子に基づいて呼び出されているメソッドを決定し、リクエストおよびレスポンスメッセージオブジェクトを正しい型にダウンキャストして、直接呼び出します。GetRequestPrototype
およびGetResponsePrototype
: 指定されたメソッドの正しい型のリクエストまたはレスポンスのデフォルトインスタンスを返します。
次の静的メソッドも生成されます
static ServiceDescriptor descriptor()
: このサービスが持つメソッドとその入力型と出力型に関する情報を含む、型の記述子を返します。
スタブ
プロトコルバッファコンパイラは、すべてのサービスインターフェースの「スタブ」実装も生成します。これは、サービスを実装するサーバーにリクエストを送信したいクライアントによって使用されます。Foo
サービス(上記)の場合、スタブ実装 Foo_Stub
が定義されます。ネストされたメッセージ型と同様に、Foo_Stub
を Foo::Stub
とも呼べるように、typedef が使用されます。
Foo_Stub
は Foo
のサブクラスであり、次のメソッドも実装します
Foo_Stub(RpcChannel* channel)
: 指定されたチャネルでリクエストを送信する新しいスタブを構築します。Foo_Stub(RpcChannel* channel, ChannelOwnership ownership)
: 指定されたチャネルでリクエストを送信し、そのチャネルを所有する可能性のある新しいスタブを構築します。ownership
がService::STUB_OWNS_CHANNEL
の場合、スタブオブジェクトが削除されると、チャネルも削除されます。RpcChannel* channel()
: コンストラクタに渡された、このスタブのチャネルを返します。
スタブは、サービスの各メソッドをチャネルのラッパーとして追加で実装します。メソッドの 1 つを呼び出すと、単に channel->CallMethod()
を呼び出します。
Protocol Buffer ライブラリには、RPC 実装は含まれていません。ただし、生成されたサービスクラスを任意の RPC 実装に接続するために必要なすべてのツールが含まれています。RpcChannel
および RpcController
の実装を提供するだけで済みます。詳細については、service.h
のドキュメントを参照してください。
プラグイン挿入ポイント
コードジェネレータプラグイン は、C++ コードジェネレータの出力を拡張したい場合、指定された挿入ポイント名を使用して、次のタイプのコードを挿入できます。各挿入ポイントは、特に明記されていない限り、.pb.cc
ファイルと .pb.h
ファイルの両方に表示されます。
includes
: インクルードディレクティブ。namespace_scope
: ファイルのパッケージ/名前空間に属する宣言ですが、特定のクラス内には属しません。他のすべての名前空間スコープコードの後に表示されます。global_scope
: ファイルの名前空間の外側のトップレベルに属する宣言。ファイルの最後に表示されます。class_scope:TYPENAME
: メッセージクラスに属するメンバー宣言。TYPENAME
は完全な proto 名です。たとえば、package.MessageType
などです。クラス内の他のすべての public 宣言の後に表示されます。この挿入ポイントは.pb.h
ファイルにのみ表示されます。
標準コードジェネレータによって宣言されたプライベートクラスメンバーに依存するコードを生成しないでください。これらの実装の詳細は、Protocol Buffers の将来のバージョンで変更される可能性があります。