Home > 2008-07 / > This Entry 2007-09 / 実装技術 > This Entry [com : 6][Tb : 0]
純粋な構造体を除き、データメンバは常に非公開にするのは、クラス設計のイロハのようなものです。しかし、時には禁忌を犯してみるのもよいのかもしれません。それは次のような理由からです。
データメンバを非公開にしている以上、オブジェクトの初期化は必ずコンストラクタによらなければなりません。しかし、コンストラクタを用いて動的に初期化する場合、そのオブジェクトを ROM に配置することは不可能になります。
オブジェクトの宣言時に const 修飾子を付けて静的記憶域期間を持たせる場合、おそらくはそれが ROM に配置されることを期待してのことでしょう。だとすると、動的な初期化しかできないのは都合が悪いことになります。
ところで、C++ の次期標準規格に導入される予定の std::tr1::array クラステンプレートは、データメンバが公開されています。ですから、
std::tr1::arrayconst a = { 1, 2, 3 };
のように初期化子を与えて、静的に初期化することが可能です。このクラステンプレートは struct を使って定義されますが、構造体と呼ぶには、コンテナの要件を満たすメンバ関数が一通り用意されており、やや無理があります。
データメンバが公開されていないクラスには class を、データメンバを公開しているクラスには struct を用いるなどして、一見してそのクラスの持つ性質が分かるような工夫をするのもよいかと思います。
http://cppemb.blog17.fc2.com/tb.php/105-a6461fa7
Comment
つまりデータメンバの公開だけでは足りず、コンストラクタがないこと、プライベートメンバがないこと、仮想関数がないこと、基本クラスがないこと、といった条件も満たされている必要があります。
確かにやや言葉足らずでしたね。
まず、初期化子を用いての初期化は、必ずしも POD である必要はありません。array の要素が std::string とかでも構いませんから。
次に、ROM に配置できるかどうか、すなわち静的初期化だけで済むかどうかについては、POD であることが必須です。
struct A {};
struct B : A { int a, b; };
のような場合なら、静的初期化だけで済むような気もしますが、仕様上は無理ですし、実際、初期化子で初期化しようとするとエラーになりますね。
ところで、C の集成体は共用体を含みませんが、C++ の集成体は共用体を含みますね(少なくとも、8.5.1はそう読み取れます)。この辺は混乱しそうです。
もうひとつ。集成体の初期化子はメンバを記述した順に並べますが、途中にアクセス指定子が入ると、メンバのアドレスが昇順になることが保証されないのも罠ですね。(9.2)
struct A
{
public: int a;
public: int b;
};
と書くと、&a < &b とは限らなくなるようです。
これからもどんどんすばらしい情報を配信してくださいね!
楽しみにしております。