CPointの配列

[戻る]
NOR 2011/09/27(火) 10:05:07
CArray<CPoint> points;
というオブジェクトがあるとき、
PolyBezier()のような、POINT構造体配列の先頭アドレスを渡す関数に対して、
PolyBezier(hDC, points.GetData(), points.GetSize());
と、CPoint配列の先頭アドレスを渡すことは、
使いかたとしては問題無いものなのでしょうか?

> CPoint オブジェクトは、POINT 構造体を使えるところならどこでも使えます。

という記述はあるのですが、これが配列にも当てはまるのかが不明です。

手持ちのVC(6, 2005, 2008)では問題無く描画されていますが、
これは、現在のCPointが仮想関数を持たず、
POINT構造体とサイズが同じままだからたまたま動いている程度で、
動かなくなっても文句を言えないのかもしれないと疑問に思っています。

PolyBezier()のような関数にもCPoint配列を渡して構わないということは
どこかの記述から判断できますでしょうか?

仲澤@失業者 2011/09/27(火) 11:55:43
まずCArray<TYPE,・・・>の方のデータは次のように保持されています。
  TYPE* m_pData;   // the actual array of data

TYPEは本件の場合CPointですね。つまり
  CPoint *m_pData;

となるわけです。領域確保は
 m_pData = (CPoint*) new BYTE[(size_t)nAllocSize * sizeof(CPoint)];

されてます。また、GetData()は単にreturn m_pData;だけです。
つまり、PolyBezier()に渡されているのは
「CPointの配列の先頭」
ということになるわけです。
お分かりの通り、この段階ですでに判定はアウトと言えますね。

では、なぜ動くのかは、NOR さんがおっしゃる通り
class CPoint : public tagPOINT{・・・};
となっていて、言語の仕様にまかせっきりだからです。

従って結論は
 1.たまたま動いているだけ(CPoint、CArrayの仕様に依存)
となります。しかし、
 2.MFCでCPointとCArrayの仕様が変わるとは思えない
のも現実であるので、現行仕様上では、正常な動作が確約されている
ともいえますね。
当然ですが、何かメンバ変数を追加したCPointの派生クラスをCArray
したものは、何の警告も無くまったく動作しないでしょう。

自分なら
typedef CArray< POINT> P_ARY;
class P_Ary : public P_ARY{・・・・};
と、するかもしれません。CPoint *などを要求される関数は
自前で実装しなければなりませんけど、PolyBezier()を含む、
POINTの配列を扱う関数を使う以上、やむをえないと考えます(vv;)。

多分やらないとおもいますが、CPoint *を引数にする
PolyBezier()相当の関数を自前で用意することも考えられますし、
CPoint[]をPOINT[]に変換するクラスを実装することもありかもしれません。
現実的ではないとは思いますけど。

gak 2011/09/27(火) 17:58:04
> PolyBezier()のような関数にもCPoint配列を渡して構わないということは
> どこかの記述から判断できますでしょうか?
似た使い方する CDC::Polygon とか「CPoint 渡しても良いよ」と書いてあるものもある。
http://msdn.microsoft.com/ja-jp/library/cc395264.aspx
Microsoft 的には「sizeof(POINT) == sizeof(CPoint) が成り立つ」前提が仕様レベルで
存在しているのかもしれない。

ただ、lpPoints は const で良いのに 非const を要求する形でwrappしている辺り…
「CPoint 渡しても良いよ」と書いてあるドキュメントはちょっと怪しめの人が実装して
書いたドキュメントな雰囲気が無いでもない。
# 実際、PSDK(Feb 2003) 段階では「LPPOINT lpPoints」だけど、VC9 では
# 「const POINT* lpPoints」と修正入ってるし

NOR 2011/09/30(金) 20:07:16
[[解決]]
情報ありがとうございます。

たしかにCDC::Polygon()のサンプルでは、
CPoint配列の先頭アドレスをそのままPolygon()に渡していました。

この時点で、sizeof(POINT)とsizeof(CPoint)は同じでないといけないはずですし、
CPointがメンバ変数や仮想関数を持つことはあり得ない、という前提の元に、
CArray<CPoint>を渡してしまっても構わない、ということになりますね。

古いスレッドには追加発言できません。