これ何て呼びますか

環境 WIN98 VC++6.0 MFC にて

いつもお世話になります。
先日質問したばかり(QNo.682705)なのですが、やはり納得できないことがあるのでお願いします。

分かっている人からみれば、おかしな疑問と思われるかも知れませんが、私にとっては素朴に疑問が生じてしまいます。

***************************
以下2つのコードのうち、<A>は文法的にOKで<B>がNGな理由が知りたいです。

<A>
CString* str ;
str = (CString*)m_array.GetAt(i) ; //OK

<B>
CString* str ;
str = (CString*)("999") ; //NG


<A>は、m_arrayの要素にCString*を入れていて、初めて成り立つ式です。
と教わりましたが、むしろ私にはCString*以外が入っているため、CString*のキャストしていると思える。
CString*が入っているのなら、キャストする必要は無いのではないでしょうか?

ネット上で見つけたコードなため、実際の値やm_arrayの宣言がどうなっているかは確認出来ません。

そして、<A>がおかしなコードでは無いという大前提にたつと、<A>は別の表現をすると
<A>
str = (CString*)(CString*以外のポインタ) ;
となります。

そうすると<B>のコードも、"999"は999の文字列が入っているアドレスを指すポインタであるという考えが正しいとすると、
<B>
str = (CString*)(999をさすポインタ) ;
となり、おかしなコードではないと思えるのですが、考え方のどこがおかしいのでしょうか?




**************************
以下のことを教わった上であえて聞いています。


str = (CString*)("999"); は、リテラル文字列をつっこもうとしています。
リテラル文字列とCStringはまったく別物です。

A 回答 (4件)

ポインタからポインタへのキャストは


(継承が関係しない限り)
コンパイラに型情報を通知するだけで
実質何も実行されません。
なのでキャストが有効かどうかは
プログラマにかかっています。

<A>の場合
MSDNには
CPtrArray クラスは、void ポインタの配列をサポートします。
とあります。つまり、<A>のm_arrayの要素は
CStringへの実体を指すvoid型へのポインタです。
なので、このキャストは本来CStringであるものを
CStringにキャストして保存しています。

<B>の場合
char*からCString*へ変換しています。
つまり、charがあるところにCStringがあるように
認識しろとコンパイラに命令しています。
コンパイラは渋々CStringにみなしますが
実行してもうまく動作するはずがありません
(char*からCStringへのキャストは
CStringのコンストラクタが働くのですが)
    • good
    • 0
この回答へのお礼

回答ありがとうございます。


キャストについて100%誤解していました。

>har*からCString*へ変換しています。
>つまり、charがあるところにCStringがあるように
     ^^^^^^^^^^^^^^^^
>認識しろとコンパイラに命令しています。

今までずっとどうしてこんな手品のようなことが出来るのか不思議でした。が、私が勝手にそう思い込んでいただけでこんなことは出来ないのですね。

今回の一連の疑問のなぞがようやく解けた気がします。
(まだ、言い切る自身がない)

お礼日時:2003/10/19 14:04

#1 の「お礼」と,#3 の uyama33 さんのアドバイスに関してです。



> 一方、"999"は999の文字列が入っているアドレスを指すポインタであると思っていたのですが、
> これがそもそも大きな勘違いなのでしょうか?

このこと自体は正しいです。(だからといって,CString* にキャストしても良いという意味ではないです)
# 厳密には,"999" の型はポインタではなくて配列ですが。

"999" と書いただけで,コンパイラが「どこか」にメモリを確保して,
999 という文字列(実体は char 型の配列,\0 で終端)を置きます。
この文字列の寿命はプログラムの開始から終了までです。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

>このこと自体は正しいです。
あぁ良かった。これが正しくないとまた新たな悩みが生じるとこでした。

>("999" と書いただけで,コンパイラが「どこか」にメモリを確保して,
これもメモリ確保することが正しいのですね。
あぁ良かった。

補足ありがとうございます。

お礼日時:2003/10/19 18:04

一方、"999"は999の文字列が入っているアドレスを指すポインタであると思っていた



の部分ですが、
どの段階で、 999の文字列が入っているメモリーが確保されてそのアドレスが決定されるのか
について誤解されていると思います。

ソースコードの中に
"999"
とあるだけではだめで、
char bbb[4] = "789";
とすると、このコードが実行された段階で、
メモリー上に確保され、
bbb はその先頭の7を指します。

 ただし、
この、bbbを CString* に変換しようとすると
問題が起きます。
CString は、クラスですので
それへのポインターは、メモリー上に確保された
オブジェクトの先頭を指します。
 果たして、このオブジェクトの先頭は
char の配列からなっているのでしょうか?
オブジェクトの中で文字列が、どの場所に
(先頭から何バイト目に保存されているか)
どのようなかたちで保存されているかはわかりません。
(ユニコードなのか、シフトジスなのか、1文字が8ビットなのか16ビットなのか)
ですから、
bbb を CString* に変換することは無謀です。

CString str ;
str = CString("999");
とすれば、自動的な型変換によって、
オブジェクト内の適当な位置に、
適当なデータ型で保存されます。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

お礼日時:2003/10/19 17:50

 (A)のm_array.GetAt(i)は、もともとCString*を返すのかもしれません。

つまりこのとき、キャストは本来不要です。

 なぜ不要なキャストをするのかといえば、ソースコードの可読性のためです。

 他人のソースでは「実際の値やm_arrayの宣言がどうなっているかは確認出来ません」ということが、あります。その場合でも、CString*が返されることが伝わります。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

調べたところm_array.GetAt(i)はvoid *を返していたのでキャストが必要だということが分かりました。


一方、"999"は999の文字列が入っているアドレスを指すポインタであると思っていたのですが、これがそもそも大きな勘違いなのでしょうか?

お礼日時:2003/10/19 11:25

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!