K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]


新規投稿 | 開設者ホームページへ戻る | ヘルプ


[2052] セッションCookie
返信


投稿者:くまきち
2017/12/16 16:32:15

Link:
『基礎からのWebアプリケーション開発入門』のP.171のリスト5-4の後に、
「セッションCookieにPath属性が...」との記載があります。
これは、「CookieにPath属性が...」と見ればいいでしょうか?
それとも、どこかで「セッションCookie」が定義されていたでしょうか?

誤植のような気もするし、私が失念しただけのような気もするし、曖昧で申し訳ないですが、
質問させて頂きました。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2051] Re:synchronizedについて
返信


投稿者:(ぱ)こと管理人
2017/12/16 00:12:38

Link:
>これはラストアクセス時刻を設定するだけのメソッドだと思いますが、
>なぜsynchronizedにする必要があるのでしょうか?

ここで設定するthis.lastAccessedTimeはlong型ですが、
Javaではlong型については、代入自体、atomicであることが保証されていません。

https://www.jpcert.or.jp/java-rules/vna05-j.html

(intとかは良さそうなのですが、あまりそれに依存したコードは私は
書きたくないところです)


>正直、多少ズレても誰にも迷惑をかけないように思ったので質問してみました。

atomicでないということは、時刻が多少ずれるということだけでなく、
「結果がどうなるかわからない」ということだと思います。
(上記ページで引用されているJLSの記述を読むと、32ビット単位で
異なる値が混じる、ということしか起こらないようにも読めますが……)
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2050] synchronizedについて
返信


投稿者:くまきち
2017/12/14 23:47:43

Link:
『基礎からのWebアプリケーション開発入門』のP.168のリスト5-3の40行目に  

synchronized void access()

という行があります。  
これはラストアクセス時刻を設定するだけのメソッドだと思いますが、なぜsynchronizedにする必要があるのでしょうか?
正直、多少ズレても誰にも迷惑をかけないように思ったので質問してみました。
よろしかったら回答頂けると、ありがたいです。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2049] Re:『センス・オブ・プログラミング!』の正誤について
返信


投稿者:藤四郎
2017/12/13 19:42:15

Link:
お手数おかけしました。ご対応ありがとうございました。

これでこの本も一読者として安心して意味内容に集中して読み返すことができます。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2048] Re:C言語ポインタ完全制覇 第1版 4-2-1 可変長配列の配列についての質問
返信


投稿者:(ぱ)こと管理人
2017/12/13 01:51:10

Link:
>標準入出力は、テキストファイルと同じように、ファイルポインタで指定して、
>ファイルのように扱ことができる。という理解でよいでしょうか。

そういうことですね。
キーボードのような入力デバイスも、画面のような出力デバイスも、
なんでもファイルとして扱えるようにしてしまえ、というのは
もともとUNIXのアイディアで、たとえばWikipediaでUNIXを引くと
「概説」の項に以下のように書いてあります。

>各種の周辺装置やある種のプロセス間通信 (IPC) をファイルとして扱う事

ここで、「各種の周辺装置」はキーボードを含みます。

このUNIXのアイディアをMS-DOSが模倣し、Windowsでもそのまま使えるように
なっているわけです。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2047] Re:addCookieについて
返信


投稿者:(ぱ)こと管理人
2017/12/13 01:47:40

Link:
>name=COUNTERのCookieが増えないように、どこで制御しているのでしょうか?
>単純に見落としているだけかも知れないのですが、宜しかったら教えて頂きたいです!

結論から言えば、制御していません。Tomcatも同じです。

https://twitter.com/kmaebashi/status/549803263734718464

このTweetにも書いたように、何の役に立つのかはさっぱりわかりませんが、
Tomcatもそうなっているならまあいいかとそうしています。

もちろん、HttpServletResponseはリクエストの度に作り直されますし、
CookieTest.javaは1回のリクエストで1回しかaddCookie()を呼んでいないので、
同じ名前のCookieが増えることはありません。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2046] Re:flush()について
返信


投稿者:(ぱ)こと管理人
2017/12/13 01:39:52

Link:
>すごく基本的な質問かもしれないですが、たとえば「メモリ上にだけ持っていて
>ディスクに書き出していないデータがあるかもしれないのでflush」という
>イメージは分かるのですが、このサンプルの場合はメモリ上のデータの
>やり取りだけなので、flushを何のために行っているのか分かりませんでした。

このサンプルの場合はメモリ上のデータのやり取りだけですが、
それは、Henacatが手抜きのためにレスポンスボディをいったんすべて
メモリに乗せているからであり、これでは、巨大なレスポンスを返す際には
メモリが無駄になります。場合によっては、レスポンスデータを作りながら
どんどんクライアントに返してしまいたいケースもあるでしょう。
その場合、クライアントへのデータの返却を始めてしまったら、
もうレスポンスヘッダの変更はできませんから、途中でエラーが起きても
ステータスとして500とかを返すことはできず、200 OKを返すことになって
しまいますが、それでもいいからクライアントへのデータ返却を始めてしまいたい、
というニーズはあり得ます。それに対応するために、サーブレットAPIでは
「コミット」という概念を導入しています(p.119)。
http://mergedoc.osdn.jp/tomcat-servletapi-5-ja/javax/servlet/ServletResponse.html#getWriter()

その場合、HttpServletResponseのgetWriter()で得られるPrintWriterは、
バッファリングする方がよいでしょう。相手はネットワークだからです。
このように、このPrintWriterはバッファリングする(ようになる)可能性もあるため、
ここではflush()しています。
いずれにしても、バッファリングするしないはPrintWriterの実装詳細に
属することでしょうから、flush()する方が堅実なコーディングではないかと
思います。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2045] Re:『センス・オブ・プログラミング!』の正誤について
返信


投稿者:(ぱ)こと管理人
2017/12/13 00:19:10

Link:
>さて、またご面倒をおかけしますが、以下についてそちらの正誤表への追加を
>ご検討お願いいたします。年末のお忙しい時期におそれいりますが、またご都
>合のよろしいときにでもご対応いただければ幸いです。

またまたたくさんご指摘ありがとうございます。
ポカが多く申し訳ありません。

遅くなりましたが、対応させていただきました。

>後入れ先出し Last In First Out
>先入れ後出し First In Last Out

これはまあ、日本語と英語で順序を合わせなければならないというわけでも
ないでしょうから、このままとさせてください。

>> 27人集れば、誕生日が衝突する確率は50%を超えます。

私は、どういうわけか27人だと思い込んでいたようですが、
どこからその数字をおぼえたのか、まったく思い出せません…

>p.192 l.2
>> O(1/2N^2)
>
>これは誤りとまではいえないとは思いますが、一応、より細かいことをいえば
>(N-1) + (N-2) + ... + 1 = N(N-1)/2
>かと。 (つまり、無視するのは定数の係数だけでなく第二項以降も。)

正しくは1/2 N^2(つまり(N^2)/2)ではなくN(N-1)/2ですが、
さすがにN^2とN(N-1)は丸めてしまって問題ない差だと思います。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2044] addCookieについて
返信


投稿者:くまきち
2017/12/11 22:04:17

Link:
『基礎からのWebアプリケーション開発入門』のP.144のリスト4-4の33行目に 

response.addCookie(newCookie);

という行があります。 
この分は配列の最後に要素を追加するということなので、nameがCOUNTERの要素(Cookie)が既にある場合も最後に追加するように見えてしまいます。
Tomcatがうまい具合にやっているのかも知れませんが、Henacat版を見ても、やはりCOUNTER要素が増えていくように見えます。

name=COUNTERのCookieが増えないように、どこで制御しているのでしょうか?単純に見落としているだけかも知れないのですが、宜しかったら教えて頂きたいです!
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2043] Re:C言語ポインタ完全制覇 第1版 4-2-1 可変長配列の配列についての質問
返信


投稿者:884
2017/12/11 17:14:06

Link:
>これで回答になっておりますでしょうか?
 おかしな質問をしてすみません。

標準入出力とファイルの関係が理解できていませんでした。
そもそも、stdinは、FILEへのポインタ型なんですね。
標準入出力は、テキストファイルと同じように、ファイルポインタで指定して、
ファイルのように扱ことができる。という理解でよいでしょうか。



[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2042] flush()について
返信


投稿者:くまきち
2017/12/10 11:29:01

Link:
『基礎からのWebアプリケーション開発入門』のP.116のリスト3-17の80行目に

resp.printWriter.flush()

という行があります。
すごく基本的な質問かもしれないですが、たとえば「メモリ上にだけ持っていてディスクに書き出していないデータがあるかもしれないのでflush」というイメージは分かるのですが、このサンプルの場合はメモリ上のデータのやり取りだけなので、flushを何のために行っているのか分かりませんでした。
宜しければ、ここでflush()を使用している意図を教えて頂きたいです。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2041] Re:C言語ポインタ完全制覇 第1版 4-2-1 可変長配列の配列についての質問
返信


投稿者:(ぱ)こと管理人
2017/12/09 22:06:21

Link:
>ここで、このプログラムにおいて、キーボードからの入力(stdin)は、
>void read_slogan(FILE *fp, char **slogan)側で、ファイル(FILE *fp)として、
>認識されるのでしょうか。 

すみません、何が質問なのかよくわかりませんが、
リダイレクトでファイルが読み込める、という挙動についてであれば、

read_slogan < slogan.txt

というのは、read_sloganの標準入力をslogan.txtというファイルからの入力に
切り替えるという意味です。
標準入力(stdin: standard input)は、デフォルトでキーボードなのですが、
それをファイルからの入力に切り替えているので、
void read_slogan(FILE *fp, char **slogan)側では、fpからslogan.txtの
内容を読むことができます。

これで回答になっておりますでしょうか?
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2040] Re:setCookieについて
返信


投稿者:(ぱ)こと管理人
2017/12/09 21:37:53

Link:
>『基礎からのWebアプリケーション開発入門』のP.142の1行目に
>「もし、Cookieを複数送りたかったら...」とあります。
>しかし、リスト4-3の29行目からのsetCookieは値を上書きしているように見えます。
>掲示板の動作には影響無いと思いますが、誤植ではないでしょうか?

この掲示板の投稿画面のHTMLソースを開いてJavaScriptを見ていただくと、
以下のようになっています。

function set_cookie(key, val) {
  document.cookie =
  key + "=" + escape(val) + "; expires=Wed, 01-Jan-2031 00:00:00 GMT;";
}

function set_cookies() {
  set_cookie("name", document.mainForm.name.value);
  set_cookie("url", document.mainForm.url.value);
  set_cookie("password", document.mainForm.password.value);
}

同様のset_cookieの実装で、複数のCookieを設定することができています。
確かに、代入文を見るとどう見ても上書きに見えるので、妙な仕様だと思いますが、
たとえば以下のMozillaのサンプルでも
https://developer.mozilla.org/ja/docs/Web/API/Document/cookie

以下のようにあります。

document.cookie = "name=oeschger";
document.cookie = "favorite_food=tripe";
alert(document.cookie);
// displays: name=oeschger;favorite_food=tripe


[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2039] 『センス・オブ・プログラミング!』の正誤について
返信


投稿者:藤四郎
2017/12/07 22:52:50

Link:
『センス・オブ・プログラミング!―抽象的に考えること・データ構造を理解す
ること』(第1刷)

こちらも大変興味深く楽しく拝読しました。コンパクトな本に「低レベル」か
ら「高レベル」までのしくみの解説やノウハウで盛りだくさんで、これらの内
容を血肉化できれば自分にもアプリ開発は夢ではないと思いましたので、これ
からも何度も読み返すでしょう。

さて、またご面倒をおかけしますが、以下についてそちらの正誤表への追加を
ご検討お願いいたします。年末のお忙しい時期におそれいりますが、またご都
合のよろしいときにでもご対応いただければ幸いです。

p.94 本文 l.4
> 逆行していています

p.109 l.1
> 脳内になる

p.142 l.17
> Congraturations

Congratulations

p.149 l.4
> なけばならなくなってしまう。

p.177 4-3-9 スタック
> 先入れ後出し方式(LIFO--Last In First Out)

後入れ先出し Last In First Out
先入れ後出し First In Last Out
どちらも同じ事柄をさしているとは思いますが、念のためエラッタの候補としてあげます。

p.180 下から 9 行目
> 追加すべき要素
「検索すべき要素」だと思います。

p.183
> 27人集れば、誕生日が衝突する確率は50%を超えます。

https://ja.wikipedia.org/wiki/%E8%AA%95%E7%94%9F%E6%97%A5%E3%81%AE%E3%83%91%E3%83%A9%E3%83%89%E3%83%83%E3%82%AF%E3%82%B9
によれば 23 人とのことです。ちなみに、手元の計算でも
$ awk 'BEGIN { p1 = 1; p2 = 0; n = 1;
> while (p2 <= 0.5) { ++n; p1 *= (365 - n + 1) / 365; p2 = 1 - p1 }
> print n, p2 }'
23 0.507297
となりました。

p.192 l.2
> O(1/2N^2)

これは誤りとまではいえないとは思いますが、一応、より細かいことをいえば
(N-1) + (N-2) + ... + 1 = N(N-1)/2
かと。 (つまり、無視するのは定数の係数だけでなく第二項以降も。)

p.226 注 l.4
> sturct

p.250 リスト6-1 l.5
> 多重度が0..*

p.246 の記述からして「多重度が1..*」が適切と思います。

p.272 図6-16
> 行かページを

「行がページを」だと思います。

同図
> 表示対象範囲に部分的に含まれる段落

「ページをまたがる段落」だと思います。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2038] Re:『Java 謎』3.3 寄り道 - Cで継承を実現してみる
返信


投稿者:藤四郎
2017/12/07 22:30:08

Link:
ご返信ありがとうございます。

>確かに動きますが、ポインタのキャストはやはり荒業なので、
>可能であれば避けるべきかとは思います。

一歩間違えると、領域破壊や原因究明困難なバグにつながるのでしょうね。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2037] setCookieについて
返信


投稿者:くまきち
2017/12/07 22:26:27

Link:
『基礎からのWebアプリケーション開発入門』のP.142の1行目に「もし、Cookieを複数送りたかったら...」とあります。しかし、リスト4-3の29行目からのsetCookieは値を上書きしているように見えます。掲示板の動作には影響無いと思いますが、誤植ではないでしょうか?
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2036] Re:C言語ポインタ完全制覇 第1版 4-2-1 可変長配列の配列についての質問
返信


投稿者:884
2017/12/07 14:08:14

Link:
早速の&ご丁寧なご回答ありがとうございます。 
サンプルプログラムの内容が理解できました。 

OSは、Windows7です。 
統合開発環境 VS 2015のVisualC++ Win32コンソールアプリケーションでプロジェクトを作成し、サンプルプログラムの動作確認をしています。 

>stdinはキーボードからの入力なので、たとえばコマンドプロンプトで動かしているのならそのままそこでキーボードから打ち込んでも入力できますし、  

キーボードからの入力を、7回行ったら、入力した文字が画面に表示されました。 
VS 2015のコンソール画面で、slogan.txt(標語ファイル名)をキーボード入力するとファイルが読込まれると勘違いして、ファイル名を入力をしていました。 


>たとえば実行形式名がread_slogan.exeで標語ファイルがslogan.txtなら  
>read_slogan < slogan.txt  
>のようにリダイレクトで読み込ませる方法もあります。  

コマンドプロンプト上で、VS 2015で生成されたread_slogan.exeに、slogan.txt(標語ファイル名)をリダイレクトで読み込ませて、表示することができました。 


ここで、このプログラムにおいて、キーボードからの入力(stdin)は、void read_slogan(FILE *fp, char **slogan)側で、ファイル(FILE *fp)として、認識されるのでしょうか。 

度々、申し訳ありませんが、ご教示お願いいたします。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2035] Re:C言語ポインタ完全制覇 第1版 4-2-1 可変長配列の配列についての質問
返信


投稿者:(ぱ)こと管理人
2017/12/07 01:22:42

Link:
はじめまして。

>read_slogan(stdin, slogan);
>
>のstdinは、キーボードの入力と考えていますが、何を入力すればよいでしょうか。
>1週間分の標語ファイル(.txt)を読み込ませたいのですが、うまくいきません。

stdinはキーボードからの入力なので、たとえばコマンドプロンプトで動かしているのなら
そのままそこでキーボードから打ち込んでも入力できますし、
たとえば実行形式名がread_slogan.exeで標語ファイルがslogan.txtなら

read_slogan < slogan.txt

のようにリダイレクトで読み込ませる方法もあります。

実行しているOSが何かわかりませんが、リダイレクトはWindowsでもMacOSでも
Linuxでも使えるので、ぐぐってみてはいかがでしょうか。
たとえばWindowsなら、今探しましたが、以下のようなページがあります。
https://www.adminweb.jp/command/redirect/index4.html
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2034] Re:</form>について
返信


投稿者:(ぱ)こと管理人
2017/12/07 01:16:56

Link:
>『基礎からのWebアプリケーション開発入門』のP.140にあるリスト4-3について。
>59行目にある</form>は誤植でしょうか?
>些細な内容かと思いますが、念の為。
>
>仮に誤植だとすると、P.100にあるリスト3-9の37行目も同様かも知れません。

ご指摘ありがとうございます。
formを二重に閉じてしまっていますね。正誤表に上げさせていただきます。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2033] Re:『Java 謎』3.3 寄り道 - Cで継承を実現してみる
返信


投稿者:(ぱ)こと管理人
2017/12/07 01:11:57

Link:
>また、『C 言語ポインタ完全制覇』改訂版の発売おめでとうございます。

ありがとうございます。

>>MethodTableIndexは利用者に晒す必要はないので、Shape.hに移動するのは 
>>よろしくないかと思います。
>
>そうしますと、自分自身とサブクラスに公開する "ShapeP.h" にではいかがで
>しょう。

サブクラスは各メソッドのインデックスを知る必要はあるでしょうから、
ShapeP.hに置くことになるかと思います。本にあるPolyine.cとかでは、
配列の初期化子にしれっと書くことで、DRAW_INDEXを見ずに済んでいますが……

>ひとつ、またまぬけかもしれない質問を――
>p.179 List 3.16 l.19 などで super.super.…を回避するのに
>    ((Object *)p)->classDescriptor = &polylineClassDescriptor;
>とかやるのはやっばりまずいですか。 (一応、動いてる模様ですが…。)

確かに動きますが、ポインタのキャストはやはり荒業なので、
可能であれば避けるべきかとは思います。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2032] C言語ポインタ完全制覇 第1版 4-2-1 可変長配列の配列についての質問
返信


投稿者:884
2017/12/06 13:57:34

Link:
はじめまして。

現在、C言語ポインタ完全制覇 第1版で学習しています。

4-2-1 可変長配列の配列で疑問があり、質問させていただきます。

List4-5 read_slogan.cで、

read_slogan(stdin, slogan);

のstdinは、キーボードの入力と考えていますが、何を入力すればよいでしょうか。
1週間分の標語ファイル(.txt)を読み込ませたいのですが、うまくいきません。

ご教示お願いいたします。

---------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void read_slogan(FILE *fp, char **slogan)
{
    char buf[1024];
    int  i;

    for (i = 0; i < 7; i++) {
        fgets(buf, 1024, fp);

        /* 改行文字を削除 */
        buf[strlen(buf)-1] = '\0';

        /* 標語ひとつ分の領域を確保 */
        slogan[i] = malloc(sizeof(char) * (strlen(buf) + 1));

        /* 標語の内容をコピー */
        strcpy(slogan[i], buf);
    }
}

int main(void)
{
    char *slogan[7];
    int i;

    read_slogan(stdin, slogan);

    /* 読み込んだ標語を表示する */
    for (i = 0; i < 7; i++) {
        printf("%s\n", slogan[i]);
    }

    return 0;
}

---------------------------------
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2031] </form>について
返信


投稿者:くまきち
2017/12/05 21:14:35

Link:
『基礎からのWebアプリケーション開発入門』のP.140にあるリスト4-3について。
59行目にある</form>は誤植でしょうか?
些細な内容かと思いますが、念の為。

仮に誤植だとすると、P.100にあるリスト3-9の37行目も同様かも知れません。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2030] Re:『Java 謎』3.3 寄り道 - Cで継承を実現してみる
返信


投稿者:藤四郎
2017/12/04 19:57:15

Link:
今回も懇切なご説明ありがとうございます。

また、『C 言語ポインタ完全制覇』改訂版の発売おめでとうございます。わた
しも、 Java の学習曲線がそれなりにゆるやかに感じられるようになったら、
ぜひ拝読して C もちゃんと理解できるようになりたいと思います。

>趣旨としては、複数階層の継承を実現するにはどうすればよいか、ということで 
>よいでしょうか。 

はい。

>MethodTableIndexは利用者に晒す必要はないので、Shape.hに移動するのは 
>よろしくないかと思います。

そうしますと、自分自身とサブクラスに公開する "ShapeP.h" にではいかがで
しょう。

>ただ、上記mtの型は、宣言にあるとおり「voidを返す関数へのポインタへのポインタ」 
>なので、sizeof(mt)ではポインタのサイズしか取れません。 

初心者らしくやっぱりやらかしてしまいました。

じつは、いただいたご説明をコードに落とすべくそれなりに格闘したのですが、
お恥ずかしいことにとりあえず挫折します。『C 言語ポインタ完全制覇』改訂
版の拝読後に捲土重来を期して…。

ひとつ、またまぬけかもしれない質問を――
p.179 List 3.16 l.19 などで super.super.…を回避するのに
    ((Object *)p)->classDescriptor = &polylineClassDescriptor;
とかやるのはやっばりまずいですか。 (一応、動いてる模様ですが…。)

# わたしの理解吸収力がたんにしょぼいだけといえばそれまでではありますが、
# 『Java 謎+落とし穴』は読み返すたびに新たな発見があります。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2029] Re:『Java 謎』3.3 寄り道 - Cで継承を実現してみる
返信


投稿者:(ぱ)こと管理人
2017/12/02 00:40:59

Link:
>『Java 謎+落とし穴 徹底解明』 3.3 寄り道 - Cで継承を実現してみる
>p.177 - List 3.11 - 3.22 について、 たとえば ExtendedPolyline を追加す
>るとしたらどうするのか、つたないながら考えてみました。

趣旨としては、複数階層の継承を実現するにはどうすればよいか、ということで
よいでしょうか。

>まず、 Shape.c の MethodTableIndex を Shape.h に移動するのはまずいでしょ
>うか。しかし、そうしたとして、あとは以下のファイルを改変または追加しました。
>(なお、 Shape は abstract 相当と理解しております。)

Shape.hは利用者側(たとえばmain.c)でも#includeするヘッダファイルですが、
MethodTableIndexは利用者に晒す必要はないので、Shape.hに移動するのは
よろしくないかと思います。

>/* このへんがとりわけリアリティにかけるのかも…… */
>void initExtendedPolyline(void) {
>  ClassDescriptor *cd = getPolylineClassDescriptor();
>  void (**mt)() = cd->methodTable;
>  memcpy(methodTable, mt, sizeof(mt));
>  methodTable[(int)DRAW_INDEX] = drawExtendedPolylineImpl;
>}

まず、このmemcpy()は、ExtendedPolyline独自のmethodTableについて、
いったんそのスーパークラスであるPolylineのmethodTableをコピーしておいて、
その中で特定のメソッドだけをオーバーライドするためのものかと思います。
ただ、上記mtの型は、宣言にあるとおり「voidを返す関数へのポインタへのポインタ」
なので、sizeof(mt)ではポインタのサイズしか取れません。
この形で複数階層の継承を実現するには、スーパークラスのメソッドテーブルに
何個のメソッドがあるのかを、できればコンパイル時に知りたい(メソッドテーブルを
malloc()で確保するなら別ですが、静的に決まる数の要素をmalloc()で確保するのは
避けたい)わけで、そうなると、各クラスのヘッダファイルを、
アプリケーションに公開するもの、自分自身のサブクラスのみに公開するものに
分ける必要があるかと思います。実際、Xt Intrinsicsや
http://kmaebashi.com/programmer/c_yota/inherit.html
こちらのサンプルでは、Polyline.hとPolylineP.hを分けています。

また、クラスディスクリプタを初期化する関数を用意するのは良いとして、
それを、利用者側(main.c)から呼び出させるのは美しくないですよね。
この場合、Objectクラスのクラスディスクリプタに、
・クラスディスクリプタが初期化されているかどうかのフラグ
・スーパークラスのクラスディスクリプタへのポインタ
・クラスディスクリプタを初期化する関数へのポインタ
を持たせてやって、
PolylineやRectangleのような各クラスで、それぞれのクラスディスクリプタへの
ポインタをグローバル変数として公開し、

/* PolylineClassがPolylineのクラスディスクリプタへのポインタ */
Polyline *polyline = new_instance(PolylineClass);

このnew_instanceの中で、

渡されたポインタの指す先のクラスディスクリプタが初期化されていなければ、
そのクラスディスクリプタを初期化する関数を呼び出す。ただしそれを、
親クラスへ遡りながら親クラスから順に行う。

という処理を行えば、クラスディスクリプタの初期化処理を
フレームワーク内で行えるのではないでしょうか。
また、new_instanceの中では、各クラスの「コンストラクタ」を
呼ぶこともできます。
こちらのサンプルでは、
http://kmaebashi.com/programmer/c_yota/inherit.html
クラスディスクリプタを初期化する関数へのポインタclass_initializerを
Coreのクラスディスクリプタに持たせているにもかかわらず、
それを呼び出す処理がどこにも書いてないですね…… orz
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2028] 『Java 謎』3.3 寄り道 - Cで継承を実現してみる
返信


投稿者:藤四郎
2017/11/29 00:44:18

Link:
『Java 謎+落とし穴 徹底解明』 3.3 寄り道 - Cで継承を実現してみる
p.177 - List 3.11 - 3.22 について、 たとえば ExtendedPolyline を追加す
るとしたらどうするのか、つたないながら考えてみました。

ここのところいろいろご面倒をおかけしておりますが、またよろしければご叱
正いただけると幸いです。

(なお、
http://kmaebashi.com/programmer/c_yota/inherit.html
も拝見しましたが、申し訳ないことにいまのわたしには難解でした。)

まず、 Shape.c の MethodTableIndex を Shape.h に移動するのはまずいでしょ
うか。しかし、そうしたとして、あとは以下のファイルを改変または追加しました。
(なお、 Shape は abstract 相当と理解しております。)

---- Polyline.h -----------------------------------------

#ifndef POLYLINE_H_INCLUDED
#define POLYLINE_H_INCLUDED
#include "Shape.h"
#include "Point2D.h"

typedef struct {
  Shape super;
  int nPoints;
  Point2D *point;
} Polyline;

Polyline *createPolyline(void);
void drawPolyline(Polyline *polyline);
ClassDescriptor *getPolylineClassDescriptor(void);

#endif /* POLYLINE_H_INCLUDED */

---- Polyline.c -----------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include "Polyline.h"

static void drawPolylineImpl(void);

static void (*methodTable[])() = {
  drawPolylineImpl
};

static ClassDescriptor polylineClassDescriptor = {
  methodTable
};

ClassDescriptor *getPolylineClassDescriptor(void) {
  return &polylineClassDescriptor;
}

Polyline *createPolyline(void)
{
  Polyline *p = malloc(sizeof(Polyline));

  p->super.super.classDescriptor = &polylineClassDescriptor;
  p->nPoints = 0;
  p->point = NULL;

  return p;
}

void drawPolyline(Polyline *polyline)
{
  polyline->super.super.classDescriptor->methodTable[(int)DRAW_INDEX]();
}

static void drawPolylineImpl(void)
{
  fprintf(stderr, "Polylineを描画\n");
}

---- ExtendedPolyline.h ---------------------------------

#ifndef EXTENDED_POLYLINE_H_INCLUDED
#define EXTENDED_POLYLINE_H_INCLUDED
#include "Polyline.h"
#include "Point2D.h"

typedef struct {
  Polyline super;
  int nPoints;
  Point2D *point;
} ExtendedPolyline;

ExtendedPolyline *createExtendedPolyline(void);
void drawExtendedPolyline(ExtendedPolyline *extendedPolyline);

#endif /* EXTENDED_POLYLINE_H_INCLUDED */

---- ExtendedPolyline.c ---------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "ExtendedPolyline.h"

static void drawExtendedPolylineImpl(void);

static void (*methodTable[])() = {};

static ClassDescriptor extendedPolylineClassDescriptor = {
  methodTable
};

/* このへんがとりわけリアリティにかけるのかも…… */
void initExtendedPolyline(void) {
  ClassDescriptor *cd = getPolylineClassDescriptor();
  void (**mt)() = cd->methodTable;
  memcpy(methodTable, mt, sizeof(mt));
  methodTable[(int)DRAW_INDEX] = drawExtendedPolylineImpl;
}

ExtendedPolyline *createExtendedPolyline(void)
{
  ExtendedPolyline *ep = malloc(sizeof(ExtendedPolyline));

  /*
    http://kmaebashi.com/programmer/c_yota/inherit.html
    には super.super.super.... を回避する裏技が紹介されていますが……
  */
  ep->super.super.super.classDescriptor = &extendedPolylineClassDescriptor;
  ep->nPoints = 0;
  ep->point = NULL;

  return ep;
}

void drawExtendedPolyline(ExtendedPolyline *extendedPolyline)
{
  extendedPolyline->super.super.super.classDescriptor->methodTable[(int)DRAW_INDEX]();
}

static void drawExtendedPolylineImpl(void)
{
  fprintf(stderr, "ExtendedPolylineを描画\n");
}

---- draw.h ---------------------------------------------

#include "Shape.h"

void draw(Shape **shapes);

---- draw.c ---------------------------------------------

/*
  http://kmaebashi.com/bbs/thread.php?boardid=kmaebashibbs&from=1906&range=1
 */

#include <stdio.h>
#include "Shape.h"

void draw(Shape **shapes)
{
  int i;

  for (i = 0; i < 4; i++) {
    drawShape(shapes[i]);
  }
}

---- main.c ---------------------------------------------

#include <stdio.h>

#include "Shape.h"
#include "Polyline.h"
#include "Circle.h"
#include "Rectangle.h"
#include "ExtendedPolyline.h"
#include "draw.h"

int main(void)
{
  Shape *shapes[4];
  int i;

  initExtendedPolyline();

  shapes[0] = (Shape*)createPolyline();
  shapes[1] = (Shape*)createCircle();
  shapes[2] = (Shape*)createRectangle();
  shapes[3] = (Shape*)createExtendedPolyline();

  draw(shapes);

  printf("\n");
  
  drawPolyline(createPolyline());
  drawPolyline((Polyline*)createExtendedPolyline());
  drawExtendedPolyline(createExtendedPolyline());

  return 0;
}

---------------------------------------------------------
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2027] Re:『Java謎+落とし穴徹底解明』の正誤について
返信


投稿者:(ぱ)こと管理人
2017/11/27 23:50:41

Link:
>は p.74 のあやまりと思われますので、またもやこまかすぎる指摘になってしまい恐縮ですが、念のためよろしくお願いいたします。

修正しました。

何度もご指摘ありがとうございます。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2026] Re:『Java謎+落とし穴徹底解明』の正誤について
返信


投稿者:藤四郎
2017/11/26 09:27:24

Link:
正誤表の追加、ありがとうございました。

ただ、その正誤表に関して、ただし今回とは別件で、

http://kmaebashi.com/nazojava/seigo.html#p74
>p.68 8行目
>誤
>
>ことにになり
>
>正
>
>ことになり

は p.74 のあやまりと思われますので、またもやこまかすぎる指摘になってしまい恐縮ですが、念のためよろしくお願いいたします。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2025] Re:『Java謎+落とし穴徹底解明』の正誤について
返信


投稿者:藤四郎
2017/11/19 12:54:41

Link:
今回もわたしの読みの浅かったところをくわしく解説してくださってありがと
うございます。

Visitor パターンだと

>「クリックした座標との距離を算出するメソッド」や
>「図形を移動させるメソッド」、「図形を囲む最小の矩形を算出するメソッド」等も

XXXVisitor として散らばってかくことになるところ……ということですね。

>私の想定したShapeRuntimeは、Shapeとセットになっており、Shapeを 
>使うあらゆるプログラムで使用するものです。

Shape と draw() を分離することだけかんがえてて、そこまで頭がまわりませ
んでした。納得です。


おかげさまで (まだまだ真にふかい理解にはほどとおいですが) Java のしく
みがかなりわかってきたような気がします。『センス・オブ・プログラミング!』
等々も参考にさせていただきつつ、小規模なアプリケーションを自作できるよ
うになるのが目標です。

今後も質問等をさせていただくこともあると思いますが、その折にもよろしく
お願いいたします。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2024] Re:『Java謎+落とし穴徹底解明』の正誤について
返信


投稿者:(ぱ)こと管理人
2017/11/19 00:13:43

Link:
>としか思いつけませんでした。しかし、こうだと Visitor 同様「 if else を
>ずらずら」になるように思います。

AbstractFactoryとその実装クラスにcreateXXXRuntime()がずらずら並ぶ、
というのは確かにそうですが、draw()だけでなく、
「クリックした座標との距離を算出するメソッド」や
「図形を移動させるメソッド」、「図形を囲む最小の矩形を算出するメソッド」等も
DrawShapeRuntimeに入れておけば、それを呼び出すところでは、図形の種類分だけの
何かをずらずら書く必要はなくなりますよね。
(DrawShapeRuntimeというのは、draw()メソッドだけ持っていそうな名前なので、
この名前はよくなかったかもしれません…… 付けるならDrawToolShapeRuntimeでしょうか)

>また、各 Shape のコンストラクターに
>AbstractFactory の分の引数を追加することになるのでしょうか。

それでもよいですし、ShapeRuntimeは、ドローツールならドローツール、
図形ファイルを読み込んで解析するプログラムならそのプログラム、
というように、プログラムの種類ごとに作ることになるのでしょうから、
どこかにstaticに持ってしまってもよいような気もします。
Javaだと、「図形ファイルを読み込んで解析するプログラム」では
デシリアライザを使って図形ファイルを読み込むのでしょうから、
その場合、ShapeRuntimeはreadObject()でくっつけることになりますから、
AbstractFactoryはそこから手が届くところにある必要がありますし。


>ちなみに、つぎのようにするのではだめでしょうか。

>abstract class ShapeRuntime {
>    protected DrawShapeRuntime drawShapeRuntime;
>    
>    abstract DrawShapeRuntime getDrawShapeRuntime();
>}

もともとの趣旨として、
「Shapeクラスは、ドローツールだけでなく、たとえばドローツールで作った
ファイルを解析する別のプログラムでも使う」
というものがありました。

その点で、このShapeRuntimeは、「ドローツール」と、
「ドローツールで作ったファイルを解析する別のプログラム」で
共用するものなのでしょうか。

私の想定したShapeRuntimeは、Shapeとセットになっており、Shapeを
使うあらゆるプログラムで使用するものです。そして、ドローツールだけで
使うShapeRuntimeのサブクラスがDrawShapeRuntimeです。
同じ趣旨なのであれば、ShapeRuntimeのメソッドの戻り値の型として、
DrawShapeRuntimeが出てきてしまっては、ShapeRuntimeがドローツール
専用品に依存してしまうので、よろしくないのではないでしょうか。
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[2023] Re:『Java謎+落とし穴徹底解明』の正誤について
返信


投稿者:藤四郎
2017/11/16 19:37:20

Link:
詳しく解説くださり、ありがとうございます。 adjustBoundary() に引数をわ
たすとなると、ワールド座標系版とデバイス座標系版にわけるのがすじという
ようなはなしになってしまうので、引数なしの adjustBoundary() を採用され
たというわけですね。疑問がすっきり解消しました。

さて、 p. 228 「別の方法」について、そもそも Abstract Factory パターン
をよくわかってないのでとんだ見当はずれだったらもうしわけありませんが、
「各 Shape のオブジェクトに……くっつける」ときに使い、「いざ描画すると
きには…… DrawShapeRuntime にダウンキャスト」するとなると、

abstract class AbstractFactory {
    abstract PolylineRuntime createPolylineRuntime(Polyline polyline);
    abstract CircleRuntime createCircleRuntime(Circle circle);
    abstract RectangleRuntime createRectangleRuntime(Rectangle rectangle);
}

class DrawFactory extends AbstractFactory {
    PolylineRuntime createPolylineRuntime(Polyline polyline) {
        return new DrawPolylineRuntime(polyline);
    }
    // ...
}

としか思いつけませんでした。しかし、こうだと Visitor 同様「 if else を
ずらずら」になるように思います。また、各 Shape のコンストラクターに
AbstractFactory の分の引数を追加することになるのでしょうか。

ちなみに、つぎのようにするのではだめでしょうか。

abstract class Shape {
    ShapeRuntime shapeRuntime;
}

abstract class ShapeRuntime {
    protected DrawShapeRuntime drawShapeRuntime;
    
    abstract DrawShapeRuntime getDrawShapeRuntime();
}

class PolylineRuntime extends ShapeRuntime {
    
    PolylineRuntime(Polyline polyline) {
        this.drawShapeRuntime = new DrawPolylineRuntime(polyline);
    }

    DrawShapeRuntime getDrawShapeRuntime() {
        return this.drawShapeRuntime;
    }
}

interface DrawShapeRuntime {
    void draw(Drawable d);
}

class DrawPolylineRuntime implements DrawShapeRuntime {         // 「 PolylineRuntime を継承」無用
    private Polyline polyline;
    
    DrawPolylineRuntime(Polyline polyline) {
        this.polyline = polyline;
    }
    
    public void draw(Drawable d) {
        Point2D[] points = this.polyline.getPoints();
        for (int i = 0; i < points.length - 1; i++) {
            d.drawLine(points[i].getX(), points[i].getY(),
                       points[i+1].getX(), points[i+1].getY());
        }
    }
}

class Polyline extends Shape {
    private Point2D[] points;

    public Polyline(Point2D[] points) {
        this.points = points;
        this.shapeRuntime = new PolylineRuntime(this);
    }
    
    public Point2D[] getPoints() {
        return this.points;
    }
}

// Circle, Rectangle の対応分は略

/*
XDrawCanvas の paint() の
        shape.draw(this.drawWindow);

        shape.shapeRuntime.getDrawShapeRuntime().draw(this.drawWindow);        // 「DrawShapeRuntime にダウンキャスト」不要
に変更。
*/
[ この投稿を含むスレッドを表示] [ この投稿を削除]



[ より古い投稿]