C++相談室 part61
..
113:デフォルトの名無しさん
08/03/19 12:28:38
std::cinで文字や数値を入力するとバッファに改行文字が残るようで、
その後に std::getline(std::cin, buf, '\n'); とかやらせると残った改行文字だけ読み込んでしまいます。
バッファをクリアする方法がないかと調べてみたのですが、
環境に依存せず確実にクリアする方法はない、という記述がありました。
こういう場合はそもそもstd::cinを使わないようにするのがよいのでしょうか?
fgetsとかを代わりに使えば改行文字まで読み込んでくれるみたいなのですが、
std::cinの方がすっきりしたコードになるので、他に問題を回避する方法がないか探しています。
114:デフォルトの名無しさん
08/03/19 12:45:02
>>113
cin.ignoreを呼ぶとかcin.getを繰り返すとかで十分では?
115:デフォルトの名無しさん
08/03/19 12:49:09
ああ、なるほど。
この場合はバッファに残るのが改行文字一個だけと分かってるから、それで十分なんですね。
ありがとうございました。
116:デフォルトの名無しさん
08/03/19 15:15:14
cinから一行読み込み+istringstreamで良くね?
string line;
getline(cin,line);
stringstream linestream(line);
117:デフォルトの名無しさん
08/03/20 15:40:59
#define Max 1000
みたいなのを、グローバル変数を使って
const int Max = 1000;
とした方が良い(型指定ができるから)、と読んでる本で出てきました。
色んな所で「グローバル変数はできるだけ使うな」と言われていたのでびっくりしてしまったのですが、
こうやってconstにして#defineの代わりにするのは例外的によく使われるものなのでしょうか?
118:デフォルトの名無しさん
08/03/20 15:46:50
defineよりはマシってだけの話。
119:デフォルトの名無しさん
08/03/20 15:52:08
グローバル変数の議論とはまた別の話しだろ
120:デフォルトの名無しさん
08/03/20 15:56:36
>>117
グローバル変数がダメなだってだけ覚えてて、なぜダメなのか考えたこと無いみたいだね?
大雑把に言うとどこで変更してるか分からないから把握しづらいといったとこです
const つけた場合(やろうと思えばできるけれど)変更できないので、そういう害は無い
121:デフォルトの名無しさん
08/03/20 15:58:48
あほすぎるw
122:デフォルトの名無しさん
08/03/20 16:53:57
別の翻訳単位で参照する可能性のある“変数”ならグローバル変数を使う。
別の翻訳単位で参照する可能性のある“数値”なら#define定義のあるヘッダを各自インクルードすればいい。
123:デフォルトの名無しさん
08/03/20 17:11:37
>>122
なに言ってんの?w
124:デフォルトの名無しさん
08/03/20 17:12:31
const ついてるやつはグローバル定数と呼ぶべきもの。
125:デフォルトの名無しさん
08/03/20 17:17:00
>>117
グローバル変数に限らず、「○○はよくない」などと言われる物は絶対にダメという意味ではない。
○○以外の有効な手段があればそれを選べという意味であって、○○が有効となる限られたケースでは使っていい。
126:デフォルトの名無しさん
08/03/20 17:18:31
理由を理解せずに規約に従っても意味がない事の典型だな
127:デフォルトの名無しさん
08/03/20 18:31:27
>117
基本的にマクロは(特定の使い方以外)使わない方がいい。
マクロはプリプロセスで処理されてしまうため、コンパイルエラー時に酷い目に会う。
グローバル変数も使い方が難しいけど、コンパイラが識別できるものなのでマクロより余っ程マシ。
エラーが発生してもあくまで“変数”なので、マクロと違って識別名が普通に表示されるので
トレースしやすい。
因みに言うと、グローバル変数にするかどうかは「その値がどの範囲まで影響するか/正しいか」というのを
考えて決めるべき。プログラム中で一意な定数は積極的にconstグローバル変数にすべきだわな。
……しかし、こういう「疑問点を自ら追求する力を付ける」のがゆとり教育だったはずなんだけどね。
やっぱり失敗だったのか……
128:デフォルトの名無しさん
08/03/20 18:37:15
なんで勝手に117をゆとり教育を受けた人認定してるんだよ
129:デフォルトの名無しさん
08/03/20 18:41:28
エスパーするとC++でなく、Cの人が居ます。
「const リンケージ」でググって下さい。
>>117
C++で、それはただの定数で
変数のように書き換えることは出来ません。
グローバル変数が嫌われる主な理由は、
どこで書き換えられるか、把握し辛いことにあるため、
定数には当てはまりません。
130:デフォルトの名無しさん
08/03/20 18:56:40
どう見てもゆとりです、本当にありがとうございました。
131:デフォルトの名無しさん
08/03/20 20:02:06
1. マクロ定数はアドレスを完全に持たない。
(const 定数はアドレスを取得しようと思えばできるが、
アドレスを取得しさえしなければデータがデータメモリ上に置かれるとは限らない)
2. const 定数は名前空間に所属できる。
(マクロには名前空間がないため、名前被りが発生する可能性が大きい)
3. 値を求めるのに何らかの処理を伴う定数を使う場合、マクロだと毎回コードが埋め込まれてしまう。
(最適化が効く範囲ならいいのだが)
4. const 定数の方がコンパイルエラーが読みやすい。
(マクロの場合、置換後のテキストを元にしてエラーが出力されてしまう)
5. マクロの場合、型を明確に指定するには明示的なキャストが必要になる場合がある。
(見た目の問題でしかないと言われればそれまでだが)
6. ローカルスコープ内であっても、マクロ定数と同名の識別子を作ることはできない。
(作れない方がいいという意見もあるのかもしれないが)
7. const 定数を使うと副作用が一切無いことが明示される。
(キャスト演算子をオーバーロードしているクラスのオブジェクトの場合は例外だが)
132:デフォルトの名無しさん
08/03/21 11:21:21
質問があります。
動的配列を解放するときは要素数とかバイト数を指定しなくても
delete [] p;
でokですが、これはポインタpが指している動的配列の先頭バイトの
前に4byteの領域が確保されていて、ここに動的配列のバイトサイズ
が格納されているから、delete時にサイズを指定する必要がないと
聞いたことがあります。
しかし、動的配列の総バイト数はわかるとしても、要素のバイト数
の情報はどこに格納されているのでしょうか?
int *p; なら1要素のバイト数は4、double *p; なら1要素のバイト数は
8ですが、実行時にこの情報はどこから取得するのでしょうか?
ポインタpそのものは先頭1バイトのアドレス情報しか保持して
ませんから、こういう疑問をもった次第です。
133:デフォルトの名無しさん
08/03/21 11:30:24
ポインタそのものにそのアドレスに何が格納されてるかの情報は含まれてる。
そうでなければ cout << *p << endl; とかやったときに何が表示されるか未定義になってしまうじゃないか。
134:デフォルトの名無しさん
08/03/21 12:15:53
>ポインタそのものにそのアドレスに何が格納されてるかの情報は含まれてる。
ありがとうございます。
ポインタは、単に先頭バイトのアドレスを格納する4バイトの記憶
場所をもっているだけでなく、動的データ(または動的配列の要素)
のバイト数とか、データが文字なのか、整数なのか、実数なのか、
といった情報も裏側にもっている。これらの情報はポインタが指す
動的変数や動的配列側にではなく、ポインタ側にある。
という理解でよろしいでしょうか?
135:デフォルトの名無しさん
08/03/21 12:21:02
>>134
違う。ポインタの型によって静的に決まる
136:デフォルトの名無しさん
08/03/21 12:21:50
静的に型付けされてるからそんなものは要らない。
137:デフォルトの名無しさん
08/03/21 12:23:04
まさかvoid*をdeleteしてないよな…
あとポインタが4バイトとは限らないぞ。
138:デフォルトの名無しさん
08/03/21 12:30:09
うーん、わからなくなってきました。
文字型変数、整数型変数、実数型変数がコンパイル時に静的に
型付けされているのと同じというのは概念的にわかります。
しかし、自分が質問しているのは、その静的な型付けをどのよう
なしくみで実装しているのか?ということだろうと思います。
この段階にくると、コンパイラやアセンブラが理解できないと
無理なんでしょうけど。
139:デフォルトの名無しさん
08/03/21 12:50:07
実行時に要素のバイト数は、どこにも格納されてない。
と、考えて良い。
コンパイルする時点では、当然型が分かるので、それを使う。
この段階というか、かなり基礎。
※RTTIは上記が理解出来た上で。
140:デフォルトの名無しさん
08/03/21 12:59:28
>>138
いっぺん、自作クラスにoperator newとoperator deleteを実装してみればいいんじゃないかな。
乱暴な説明だけど、C++には「確保/削除するバイト数を受け取る、new/delete一族の大ボス的存在」である
::operator new(size_t)と::operator delete(void*, size_t)があって(他にも多重定義があるけど、とりあえず今はこの2例)、
たとえば int* p = new int; なんてのは、int* p = ::operator new(sizeof(int)); みたいにコンパイル時に解釈される。
同じく、後にdelete p; が出てきたら、pがint型のポインタなのはコンパイラにはわかるから(てか俺等にだってわかる)、
こっちは ::operator delete(p, sizeof(int)); になる。
141:デフォルトの名無しさん
08/03/21 13:24:09
>>138
>int* p = new int; なんてのは、int* p = ::operator new(sizeof(int));
int *p= new int [100]; は int *p=::operator new(sizeof(int)*100);
みたいになるんでしょうけど、要素のサイズが2バイトなのか4バイト
なのかの情報をコンパイル時にポインタに付加しておかないと、p[i]の
アクセスがうまくいかないのではないかと思うのですが、どうでしょうか?
142:デフォルトの名無しさん
08/03/21 13:25:59
>>141
p[i]のpの型はコンパイル時に分かってるんだから
143:デフォルトの名無しさん
08/03/21 13:44:43
まあ、強いて言えば、生成されたコード内に埋め込まれているって感じなのかな。
delete[] p;するときに、各要素のデストラクタを起動しなければならないわけだけど、
要素数は p = new T[count]; のcountで、実行時に変わる可能性のあるものだから、
ポインタの前かなんかに隠しておかなければならないわけ。
ちなみに、メモリブロックを単純に解放するだけなら要素数を隠しておく必要はないよ。
free()にサイズを指定しないでしょ?
メモリマネージャはメモリブロックの総バイト数をどこかに隠しておくかもしれないけど、それは別の話。
あとは、
T *p;
for(size_t i = 0; i < count; i++){
p->destruct();
++p; //←これ
}
これの++pがどうコンパイルされるかという、>>139が言うようにC言語レベルの基本的な話。
144:デフォルトの名無しさん
08/03/21 13:56:21
>>141
> p[i]のアクセス
たとえばintが4byteの環境だとすると、p[i] と書かれた箇所はネイティブコードにおいては
「pのアドレス+i*4byteのメモリアドレスへ行ってそこから先4byte分に書き込まれているビット配列を〜」
という風に、既にintが「4byte」というミもフタも無い表現に変わっているから、型情報も何も関係無いよ。
145:デフォルトの名無しさん
08/03/21 14:27:51
>>141
p[i]というコードはコンパイルすると、アドレスはp+4*iといった意味の命令が生成される。
4が出てくる理由はpの宣言int* pによるもの(intが4byteの環境の場合)。
146:145
08/03/21 14:36:28
すまん、144と同じ事書いてしまった。
147:141
08/03/21 17:03:54
返事が遅くなってすみません。みなさん、ありがとうございます。
>>144 さんと >>145 さんの説明で
4byteという要素バイト数の情報をポインタp自体が保持して
いるのではなく、p[i]にアクセスする際にコンパイラがp+4*i
を計算する命令を生成しているだけ、ということがやっと理解
できました。
148:デフォルトの名無しさん
08/03/21 18:35:45
配列 new の場合、アップキャストは行わないから
配列のサイズは型から静的に決まる、と。
というか、アップキャストはできない。
そこが鍵だな。
149:デフォルトの名無しさん
08/03/21 18:36:13
×配列のサイズ
○要素のサイズ
150:デフォルトの名無しさん
08/03/21 18:44:36
C++ 的にはフォーマットの決まった string の中から数字を
読み出したりするにはどうするのがお薦めなのでしょうか?
例えば
string s("# foo 30 bar 0.1 xlajkdfl;ajkds");
から 30, 0.1 を抜く場合。
int n;
double x;
sscanf(s.c_str(),"# foo %d bar %lf",&n,&x);
としたりするのですが、もっと「本来」の方法はあるのでしょうか?
どうも workaround 的な気がするので。
151:デフォルトの名無しさん
08/03/21 18:48:30
atofで一つずつ進めて数値になる所を取り出す
152:デフォルトの名無しさん
08/03/21 18:51:36
それはないな
153:デフォルトの名無しさん
08/03/21 19:53:08
自分で字句解析器を書く。
154:デフォルトの名無しさん
08/03/21 20:00:28
各種正規表現ライブラリの後方参照を使う
155:デフォルトの名無しさん
08/03/21 20:29:16
>>150
そういうのが必要になる状況ってあまり無くない?
156:デフォルトの名無しさん
08/03/21 21:08:24
>>155
俺はソースコード解析したい時によくでる。
字句解析ライブラリもってこいって話だよな・・・
157:デフォルトの名無しさん
08/03/21 21:51:06
字句解析なら分かるんだけど、>>150は何か違う気がしたんで・・・
そうなら、分割の話から入るだろうし。
もしかして自然言語文からの抽出とかかな?
158:150
08/03/21 23:35:25
皆様どうもありがとうございました。私は結構こういう必要に出会います。
主にデータファイルをフォーマットし直したり、それを処理する場合です。
例えばデータフォーマットの情報などた先頭にあったりして、その情報を
元に解析したりする場合です。無視して決め打ちする事も可能な場合も多い
ですが、安全性のために整合性をチェックしています。
>>154 さんの方法が私には合っていると思います。普段 Ruby とかも使って
いて正規表現も使っているのに惰性で C 的にを使い続けてる自分の頭の堅さ
には呆れました。基本的に以下のようなコードで対応することを考えています。
まだあまり考えていないのでもう少しエレガントに書けるだろうとは思います。
string s("# foo 30 bar 0.1 xlajkdfl;ajkds");
boost::regex r0("^# foo ([0-9.]+) bar ([0-9.]+).+");
boost::match_results<std::string::const_iterator> mr;
if(boost::regex_match(s,mr,r0)){
const int n = boost::lexical_cast<int>(mr.str(1));
const double x = boost::lexical_cast<double>(mr.str(2));
cout << n<<"\t"<<x<<endl;
}
159:デフォルトの名無しさん
08/03/22 00:19:27
>主にデータファイルをフォーマットし直したり
それまさに字句解析の範疇な気がするけど・・・w
まぁ正規表現で簡単に済めばそれで良いと思うけどね。
160:デフォルトの名無しさん
08/03/22 12:44:30
>>159
> まぁ正規表現で簡単に済めばそれで良いと思うけどね。
regex ってかなり強力だと思う。テキストから情報拾う場合
に regex では簡単に通用しない場合ってどういうケース?
161:デフォルトの名無しさん
08/03/22 13:14:39
>>160
ネストした括弧の対応を取るとか
162:デフォルトの名無しさん
08/03/22 14:07:16
そこでboost::xpressiveですよ
163:デフォルトの名無しさん
08/03/22 14:15:50
boost もいろいろあってわからんなぁ。xpressive だと簡単なのかな。
俺だと char ごと読み取って '(' ')' を +1, -1 でカウントするとか
低レベルな事を考えちゃうけど。
164:デフォルトの名無しさん
08/03/22 14:52:00
通常の正規表現では任意のネストを表現することができない。
→xpressive ではパターンの自己再帰記述が可能。
→正規表現の枠を超える表現力を持つ(文脈自由文法)。
→xpressive だとネストの対応が可能。
165:デフォルトの名無しさん
08/03/22 15:01:28
boostの文字列処理ライブラリの事ならboost本のサンプルで読めたな
166:デフォルトの名無しさん
08/03/22 15:21:10
boost 本でお薦めってある? 本あまり出てないよね。
Karlsson の本は目を通したけど感じは判ってよいけど便利な本
という感じではない。秀和から出てる稲葉さんは本厚いし内容あるのかな。
167:デフォルトの名無しさん
08/03/22 17:31:22
inabaさんのは導入+軽いリファレンスにはいいかも
おおまかな概念と使用例が載ってる
boostもう使ってるよ〜という人にはあまり必要ないかも
168:デフォルトの名無しさん
08/03/22 17:31:23
複数の派生クラスがそれぞれ値の異なるconst staticなメンバ変数をもっていて、
基底クラスへのポインタを使って読み取りたいのですが、どうすればいいでしょう
基底クラスへのポインタの配列に、いろいろな派生クラスを突っ込んでいる状態なので、
直接アクセスすることは出来ません
169:デフォルトの名無しさん
08/03/22 17:49:42
URLリンク(www.s-cradle.com)
170:デフォルトの名無しさん
08/03/22 17:54:12
>>166
C++ Template Metaprogramming
171:デフォルトの名無しさん
08/03/22 17:56:20
>>168
普通に仮想関数で
struct Base { virtual StaticMemberType GetStaticMember()=0; };
struct DerivedA : public Base {
StaticMemberType GetStaticMember { return DerivedA::staticMemember; }
};
あるいはRTTI使ってマルチメソッド。
172:171
08/03/22 17:59:13
ごめん引数1つのマルチメソッドはないなw
173:デフォルトの名無しさん
08/03/22 18:22:26
あー、関数をアクセサにすればよかったですね。何やってんだ俺
ありがとうございました
174:デフォルトの名無しさん
08/03/22 21:56:34
>>170
どうもありがとうございます。実はその本は持っていて次に読む予定。
しかし、これも洞察には優れているとは思うけど、便利な本では
ないかも。面白そうなんで期待してるけど。
175:デフォルトの名無しさん
08/03/22 22:03:15
>>174
面白くないよ。mplの単なるリファレンス。
176:デフォルトの名無しさん
08/03/23 00:53:31
DLLを読み込み、一部の機能のみを使った場合、
メモリの消費量はまるまるDLL分増えるのでしょうか
それとも使った機能の分だけ増えるのでしょうか
177:デフォルトの名無しさん
08/03/23 01:03:35
環境依存の話はスレチだけど、まるまる増えると思うよ。
178:デフォルトの名無しさん
08/03/23 01:12:30
仮想メモリはまるまる
物理メモリはコードについては使った分
データはシラネ
179:デフォルトの名無しさん
08/03/23 01:30:13
ありがとうございました
使いたいライブラリが8MBくらいあるもので、
まるまる増えるのはちょっとアレかな、と思って質問しました
改変可なので、必要な部分だけ取り出そうと思います
180:デフォルトの名無しさん
08/03/23 03:06:24
Managerクラスがあり
その機能は、一部のクラス(と言っても10個ぐらいある><)
にしか利用できないって設計の場合
一部のクラスをfriendする以外に何か方法はありませんか?
181:デフォルトの名無しさん
08/03/23 03:13:01
その一部のクラス以外はmanagerクラスのインスタンスを手に入れられないようにする。
182:デフォルトの名無しさん
08/03/23 09:41:11
>>180
freind じゃダメな理由を書いた方が答えが得られやすいと思う。
183:>>182
08/03/23 09:42:51
ミスった... orz
freind ⇒ friend
184:デフォルトの名無しさん
08/03/23 09:45:07
friend先に依存が出来るからじゃね?
普通、friendは最終手段だし
185:デフォルトの名無しさん
08/03/23 12:07:26
そんなことはない。
186:>>182
08/03/23 13:05:05
friend 先に依存って何?
187:デフォルトの名無しさん
08/03/23 13:58:48
一部のクラスだけ特別扱いするというのがManagerクラスの仕様なら、
friendによる依存は妥当だと思う。
188:デフォルトの名無しさん
08/03/23 14:45:51
一部のクラスの基底クラスとして
Manager を取得するクラスを作って、
その1つだけを friend にすれば?
189:180
08/03/23 14:58:22
friendが結構な数になってしまうんです。
下手すれば私のリアルfriendより多いぐらい
それが悔しくて
190:デフォルトの名無しさん
08/03/23 14:59:16
誰が上手い事を言えと
191:184
08/03/23 15:01:24
俺は181に一票で
192:デフォルトの名無しさん
08/03/23 15:02:43
その方法を聞いてるんだろw
193:デフォルトの名無しさん
08/03/23 15:09:28
パスワード掛ければいいんじゃないですかね
194:デフォルトの名無しさん
08/03/23 15:14:48
w
195:デフォルトの名無しさん
08/03/23 15:25:03
権限プログラミングってのも面白そうじゃないか
196:デフォルトの名無しさん
08/03/23 15:42:23
singletonなら簡単なのにな
197:デフォルトの名無しさん
08/03/23 16:01:39
思い出したw
____
|← reject| boostの中の人 singleton ユーザー
. ̄.|| ̄ ̄ ┗(^o^ )┳(`Д´)┳(^o^ )┛≡=-
|| ┏┗ ┗┗ ┏┗ ≡=-
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
198:デフォルトの名無しさん
08/03/23 16:06:07
ユーザーは欲してると思うが
199:デフォルトの名無しさん
08/03/23 16:34:52
にわかに得た知識で面白いこと考えた!
Managerのインスタンスを受け取る関数の引数に関数オブジェクトを使って
内部で一定のアルゴリズムで正しい値を返すもの(パスワードの暗号化みたいな)にのみそのインスタンスを渡してやる風にすればいいんじゃね?
更にインスタンスを受け取る関数をテンプレート化してやり、欲しい権限までのクラス型インスタンスを返すようにしてやればアクセス制限も出来て完璧!
とここまで考えてわざわざこんなことしてもオーバーヘッドが大きいだけなことに気づいた
そもそも何の意味があるんだっけか
200:デフォルトの名無しさん
08/03/23 16:45:12
だから >>188 でいいだろ、別に。
201:デフォルトの名無しさん
08/03/23 16:57:35
Managerクラスコンストラクタなどをprotectedにして、使うクラスはManagerを継承する。
202:デフォルトの名無しさん
08/03/23 17:02:41
>>188 >>199 >>201
これらの方法は、Managerクラスの許可なく好き勝手に権限のあるクラスを作れる。
そういうのを>>180は制限したいんじゃないの?
203:>>182
08/03/23 17:08:28
>>201
そう言うのは最悪。
あとから見て、継承が本当に必要だったのか、単に特定のメソッドを
使わせるために継承しているのかがわからなくなるから。
204:201
08/03/23 17:21:39
>>203
意味がよく分からないけど、、、「特定にメソッドを使わせるために継承が必要かどうかがわからなくなる」ってこと?
そんなこと言ってたら何もできない。
friendだったら、なぜfriendにしたか分からなくならないの?
friend よりいいと思うけどな。
friend じゃprivateのメンバにアクセスできてしまう。
Managerクラスを機能を利用するんだから、継承しかないでしょ。
使う側のクラスに持たせるとなると、コンストラクタとかはpublicになってしまうし。
205:デフォルトの名無しさん
08/03/23 17:40:32
継承すると
Managerの中のstaticでない変数とか勝手に作られない?
206:デフォルトの名無しさん
08/03/23 17:41:03
>>203
Manager クラスじゃなくて単に許可コントロール用の class を作る
というのは有りじゃない?そういう例をまともな本で見た記憶がある。
207:デフォルトの名無しさん
08/03/23 17:42:27
-カーズは-
2度と地球へは戻れなかった…。
鉱物と生物の中間の生命体となり
永遠に宇宙空間をさまようのだ。
そして死にたいと思っても死ねないので
―そのうちカーズは考えるのをやめた。
全部globalにすればいいじゃん
208:デフォルトの名無しさん
08/03/23 17:44:01
>>206
電波の缶詰の人のサンプルもそうだった
ライブラリ的なものを
外部からいじられないようにするためだったら
そんな感じでもいいんじゃまいか
村八分
209:デフォルトの名無しさん
08/03/23 17:47:19
Managerインスタンスを受け取るために、Managerにコールバックしてもらえばいいんじゃない?
class FriendClassA; // 前方宣言
class FriendClassB;
class Manager
{
public:
class Friend { public: virtual void authorize(Manager* m) = 0; };
void getInstance(Friend* p)
{
if( dynamic_cast<FriendClassA*>(p) ||
dynamic_cast<FriendClassB*>(p) ||
/* 権限のあるクラスかをチェック */ )
{
p->authorize(this);
}
}
};
210:デフォルトの名無しさん
08/03/23 18:25:34
それは、インスタンス取るのに時間かかるし
friendでいいじゃんって話になるも
211:デフォルトの名無しさん
08/03/23 18:40:51
速度が重要ならtemplate部分特殊化とかで。
class Manager
{
public:
template <class Unauthorized>
static void authorizedProc(unauthorizedClass * p)
{ std::cout << "not authorized" << std::endl; }
template <>
static void authorizedProc(authorizedClassA * p)
{ p->Proc(m_instance); }
// 以下許可するクラス分同じコード
private:
Manager m_instance;
};
冗長だし検証してないけど。
212:デフォルトの名無しさん
08/03/23 18:45:30
Manager を使えるクラスを作成する場合には
ファクトリクラスを通すようにする。
で、そのファクトリクラスを friend にして、
そこで Manager クラスを取得して、
各クラスにそれを渡すようにする。
設定関数は各クラスの共通基底クラスに作って、
それをファクトリクラスの friend にする。
213:デフォルトの名無しさん
08/03/23 18:46:54
先輩から聞いたのですが、extern "C" {}せずに構造体を宣言すると、
余計なクラス情報がくっつくって本当ですか?
214:デフォルトの名無しさん
08/03/23 18:52:41
そんなことは聞いた事が無いが、
特定のコンパイラでそういう事があるとかいうんだったら俺は知らない。
215:デフォルトの名無しさん
08/03/23 18:55:11
クラス情報って具体的には何なんだ?
216:デフォルトの名無しさん
08/03/23 18:57:34
>>213
マングリング名にクラス情報がくっつくって話だと思う。
217:デフォルトの名無しさん
08/03/23 18:59:55
>>214-216
言ってたのはシリコンバレー帰りの先輩です
純粋なCの構造体にするにはやはりextern "C"が必要なのですね。
ありがとうございました。
218:デフォルトの名無しさん
08/03/23 19:00:36
>>217
どこからそういう判断をしたんだ?w
219:デフォルトの名無しさん
08/03/23 19:01:52
構造体にextern "C"は関係無いだろ
220:デフォルトの名無しさん
08/03/23 19:02:10
>>216
構造体名って C でそもそも何らかのマングリングされるの?
221:デフォルトの名無しさん
08/03/23 19:07:59
C++なら名前空間やらなんやらくっつくだろ。
222:デフォルトの名無しさん
08/03/23 19:10:41
C で付かないなら
純粋な C の構造体かどうかなんて
どう区別するんだろうか。
223:>>182
08/03/23 19:46:38
>>204
まじめな話、もう一度継承についてちゃんと勉強した方がいいと思う。
(>>205 の内容を理解できてる?)
継承はアクセス制限のためにあるものじゃない。
極端な話、全てが public であったとしても、継承は有用。
これに対して、friend は純粋にアクセス制限を回避するもので、かつ
アクセス制限を回避する以外の機能は無いから、なぜ friend にしたか
がわからなくなることはない。
(もちろん、なせアクセス制限を回避する必要があるかはどっかに書いて
おく必要があるだろうけど。)
>>206
それならアリだと思う。
224:201
08/03/23 19:54:02
>>223
>>205
作られるけど。外から参照されたくないものはpublicにしなけらばいいじゃん
225:201
08/03/23 20:00:37
>>223
>継承はアクセス制限のためにあるものじゃない。
>極端な話、全てが public であったとしても、継承は有用。
だから、継承が駄目なんですか?
継承は色んな意味で使えて「わかりにくい」から駄目ってこと?
226:デフォルトの名無しさん
08/03/23 20:00:37
何かもう駄目だなここって思ったの俺だけだろうか
227:デフォルトの名無しさん
08/03/23 20:02:29
Manager 使ってる部分を別プロジェクトにする。
あとは各クラスのオブジェクト生成を外部から隠せばいい。
228:>>182
08/03/23 21:01:54
>>224
> 作られるけど。外から参照されたくないものはpublicにしなけらばいいじゃん
おいおい、ほんとにもう少し勉強してからこいよ。
引っ込みつかなくなってるだけならいいけど、マジでそう思ってるとしたら
ちょっとまずいよ。
まずい理由の一つは、private でもその変数が見えなくなるわけじゃない、
アクセスできなくなるだけだから。
この違いわかってる?
>>225
> 継承は色んな意味で使えて「わかりにくい」から駄目ってこと?
>>203 に書いたのはそう言うこと。
それしか方法が無いならしょうがないけど、friend と言うもっといい方法があ
るのにわざわざ使わないのは、別の意図があるようにとられる危険性が高い。
229:201
08/03/23 21:17:23
>>228
>マジでそう思ってるとしたらちょっとまずいよ。
Managerを継承していないクラスから参照されたくない場合はpublicにすれば良いって事だよ?
>まずい理由の一つは、private でもその変数が見えなくなるわけじゃない、
>アクセスできなくなるだけだから。
「見える」→メンバ変数の値が取得できる。(getter)
「アクセス」→メンバ変数の値が書きかえれる。(setter)
って意味で言ってるのなら
getter、setter定義してやれば、当然見えるしアクセスも可能。
230:デフォルトの名無しさん
08/03/23 21:42:53
もしかして201氏は、
Managerは1つのクライアント(Managerを使うクラスオブジェクト)の管理のみ引き受けるもので、
クライアントと同数のManagerオブジェクトが必要と考えているのではないだろうか。
231:>>182
08/03/23 22:07:14
>>229
> 「見える」→メンバ変数の値が取得できる。(getter)
> 「アクセス」→メンバ変数の値が書きかえれる。(setter)
ほら、全然理解できてない。
簡単な例でいうと、
int a, b;
class X {
private: int a;
};
class Y: public X {
int foo(){ return a; }
int bar(){ return b; }
};
ってやると、foo() の中で X::a をアクセスしようとするからエラーになるよね。
もし、C++ の private が変数を「見えなくする」なら bar() の b と同じように、
foo() は ::a を返すはずだろ?
これが、「見えなくなること」と「アクセスできなくなること」の違いなわけ。
これによる、影響は自分で調べてみてね。
>>230
まあ、それはそれでそれこそもっとよく考えろとしか言えないわけだが...
232:デフォルトの名無しさん
08/03/23 22:11:42
何でこんな残念なスレになってしまったんだ。
233:デフォルトの名無しさん
08/03/23 22:12:43
だって にちゃん だもの
234:デフォルトの名無しさん
08/03/23 22:56:01
VSyncの話したらひどいことになりそう
235:デフォルトの名無しさん
08/03/23 22:57:56
>>231
初心者スレでやれ
ウザイ
236:デフォルトの名無しさん
08/03/23 23:03:27
結局>>182って文句言ってるだけで答えて無いじゃん
237:>>182
08/03/23 23:14:58
答えは >>188 で既にでてるだろ。
まあ、10個ぐらいなら全部 friend 宣言してもいいと思うけど。
もしかして君も >>201 みたいに理解できてないやつなの? (w
238:デフォルトの名無しさん
08/03/23 23:32:29
>>188だとManager::getInstanceみたいなので取得するのと大差無いと思うが・・・
まぁ、それはともかく、>>180にfriendなどを使ってまで
制限する必要性があるのか、疑問だな。
クラスごと使わせなくするとこにfriendを使用している時点でおかしいと思う。
無名名前空間やdetails名前空間で十分なんじゃないか?
239:201
08/03/23 23:44:18
>>231
>foo() の中で X::a をアクセスしようとするからエラーになるよね。
アクセッサをManagerの方に定義することを考えていたんだけどな。
「見える」「見えない」の話じゃんくてprivateだからだろ。
>もし、C++ の private が変数を「見えなくする」なら bar() の b と同じように、
foo() は ::a を返すはずだろ?
グローバル変数よりメンバ変数を参照しにいくのは知ってます。
Managerの方に「一部のクラス」に使わせたい機能だけ、protected または public にして
一部のクラスがManagerを継承すればいい。
Manager のprivateのメンバには「一部のクラス」も参照できない。
「一部のクラス」以外にManagerクラスのインスタンスを作られるのが困る場合は
コンストラクタなどをprotectedにすればいいんでは?
「一部のクラス」に対してManagerは一つらしいので、また違ってきますが・・・・
240:デフォルトの名無しさん
08/03/23 23:58:52
これで friend いらない
-- friends.cpp
#include "A.h"
#include "B.h"
namespace
{
class Manager {};
Manger& manager();
}
void A::f() { manager().a(); }
void B::g() { manager().b(); }
241:>>182
08/03/24 00:06:26
>>238
> まぁ、それはともかく、>>180にfriendなどを使ってまで
> 制限する必要性があるのか、疑問だな。
それは、>>180 に聞いてもらわないとダメだけど、そう言う状況はありえると思うよ。
例えば、デバッグのためにマネージャの状態を直接見たりいじったりするクラスとか。
ただ 10個もあるのは、ちょっと多すぎるような気はするけどね。
>>239
頼むから、もう少し勉強してからレスしてくれ。
全然俺の言ってることが理解できてないよ。
242:デフォルトの名無しさん
08/03/24 00:08:40
で、アホなのはどっちなの?初心者なのでよく分かりません
243:デフォルトの名無しさん
08/03/24 00:51:50
>>242
やり方は色々ある。って話に落ち着けていいんじゃないのw
メイヤーズもそんなことeffective c++に書いてたでしょ。
244:デフォルトの名無しさん
08/03/24 05:56:56
>>242
「そいつの中にあるもの」の質はともかく、
「そいつの中にあるものを説明する能力」はどっこいどっこいです。
245:デフォルトの名無しさん
08/03/24 17:47:39
仮想関数を持たないクラスXとクラスYがあります。
YはXを継承しています。これらのクラスに対応する
インターフェイスのクラスIXとIYを以下のように定義しました。
しかし、コンパイルエラーでした。クラスYは抽象クラス
とみなされたようです。でも、クラスYはf()の定義も
g()の定義も持っているので抽象クラスではないように思えます。
XとYのインターフェイスを作る方法を教えて下さい。
class IX {
virtual void f() = 0;
};
class X : public IX {
void f() {}
};
class IY : public IX {
virtual void g() = 0;
};
class Y : public X, public IY {
void g() {}
};
int main()
{
Y y; // エラー(抽象クラスあるいは構造体のオブジェクトが宣言されています)
return 0;
}
246:デフォルトの名無しさん
08/03/24 17:54:22
IX IX
↑ ↑
X IY
↑↑
Y
という継承木になっている。
X::IX::f は定義されているが、
IY::IX::f は定義されていない。
インタフェースクラスを作るなら、IX を仮想継承する必要がある。
ただ、それでも Y で f を定義する必要がある。
あと、インタフェースクラスに限らず、基底クラスには
必ず仮想デストラクタを定義するのを忘れないように。
247:デフォルトの名無しさん
08/03/24 18:14:09
>>246
ありがとうございます。
以下のように変更したらエラーが警告になりました。
この警告は無視していいような気がします。
>あと、インタフェースクラスに限らず、基底クラスには
>必ず仮想デストラクタを定義するのを忘れないように。
OKです。
class IX {
virtual void f() = 0;
};
class X : virtual public IX {
void f() {}
};
class IY : virtual public IX {
virtual void g() = 0;
};
class Y : public X, public IY {
void g() {}
};
int main()
{
Y y; // 警告('Y' : 2 つ以上のメンバが同じ名前を持っています。'X::f' から継承します。)
return 0;
}
248:デフォルトの名無しさん
08/03/24 18:50:40
Y::f では X::f と IY::f のどっちの実装を使えばいいのか分からないというもの。
まあ、今回の場合は IY::f に実装がないから X::f を使いますよという警告だけど、
Y に void f() { X::f(); } と書いておくのが無難。
249:デフォルトの名無しさん
08/03/24 19:06:35
class T
{
T( int );
}
を
T *T_array = new T [100];
は出来ないじゃん?
#placement new使えってのはなしで。
std::vectorはどうやってこういうコンストラクタが引数を持ってるクラスを受け入れてるの?
250:デフォルトの名無しさん
08/03/24 19:07:20
placement newで
251:デフォルトの名無しさん
08/03/24 19:11:33
>>248
上の例では void f() 1個だけですが、実際のIXは純粋仮想関数を
22個もっています。Yに22個の関数をわざわざ定義するのはなんだか
無駄な気がするのですが。。。
252:デフォルトの名無しさん
08/03/24 19:18:29
>>251
まあ、面倒なら今のところは無視してもいいかもしれない。
コメントでも書いとこう。
253:デフォルトの名無しさん
08/03/24 19:26:44
>>241
頼むから、もう少しまともな説明してくれ。
254:デフォルトの名無しさん
08/03/24 19:31:33
>>252
わかりました。ありがとうございました。
255:デフォルトの名無しさん
08/03/24 19:31:46
friend 使うと「一部のクラス」が増えるとManagerも弄らないと駄目だな。
256:デフォルトの名無しさん
08/03/24 19:34:11
拡張性を敢えて犠牲にするなら、個別に friend するしかない。
拡張性もある程度考慮するなら基底クラス作ってそれだけ friend 。
あとは本人がどうしたいか、だな。
257:デフォルトの名無しさん
08/03/24 20:12:41
>>253
非常に初歩的な内容だし、あの説明で理解できないなら、
もうあきらめた方がいいぞ。
258:デフォルトの名無しさん
08/03/24 22:58:50
IDすら出ない板で煽り煽られ大変ですな
259:180
08/03/24 23:04:33
私の為に喧嘩しないで><。
260:デフォルトの名無しさん
08/03/24 23:59:31
struct B{
struct P{ B *temp; }
B( P p ){ swap( *this, *(p.temp) ); }
operator P (){ P p; p.temp = this; return p; }
};
B Return(){ return B(); }
void Accept( B &b ){};
------------
Accept( Return() ); //Error
俺、何間違えてるの?
261:デフォルトの名無しさん
08/03/25 00:06:50
設計?
262:デフォルトの名無しさん
08/03/25 00:07:13
エラーメッセージはキチンと書く
263:デフォルトの名無しさん
08/03/25 00:09:50
;
264:デフォルトの名無しさん
08/03/25 00:11:00
質問の仕方
265:デフォルトの名無しさん
08/03/25 00:11:54
>>263
266:デフォルトの名無しさん
08/03/25 00:11:55
Bにデフォルトコンストラクタないからとか?
267:デフォルトの名無しさん
08/03/25 01:12:43
Humanクラスを基底クラスとするTanakaやAsouやIshikawaクラスがあるとします
Humanは抽象クラスとして用いるつもりです
このときHumanにあるstaticメソッドを一回だけ呼び出したいときってどうすればいいでしょうか?
Humanのコンストラクタで呼び出したとすると、TanakaやAsouのコンストラクタでも呼び出されますよね
static bool initのような変数をフラグとして使う方法は思いついたのですが、
もっとスマートな方法はないのでしょうか?
268:デフォルトの名無しさん
08/03/25 01:16:38
シングルトンやそれに関わるC++の実装は非常に面倒くさくて
自分で一からやろうと思うとどうしても乱雑になる。
マルチスレッドが入ってくるともっと面倒くさくなる。
269:デフォルトの名無しさん
08/03/25 01:25:21
>>260
人生、かな?
270:デフォルトの名無しさん
08/03/25 01:49:26
>>267
そのメソッドを呼び出したいのは、Human派生のオブジェクトを生成したタイミングなの?
271:267
08/03/25 02:13:35
>>270
そうですね
Human派生のオブジェクトを生成する前に呼び出しても構わないのですが
272:デフォルトの名無しさん
08/03/25 02:30:23
>>271
であれば、全てが始まる前に自分で一度だけ呼ぶのが良いと思うな。
273:デフォルトの名無しさん
08/03/25 02:31:52
>>272
それはstaticな変数をフラグにするよりダメじゃねぇかw
274:267
08/03/25 02:39:11
>>272
あぁそうか、そもそもstaticなメソッドなわけだから
int main(){
Human::onlyOnceCalled()
みたいなかんじで
最初の方で適当に呼んでおくってのもありかもしれませんね
一回だけしか呼ばないって保証がないような気もしますが
275:デフォルトの名無しさん
08/03/25 02:49:38
>>274
必ず最初に読んでしまってよいなら、クラスにスタティックなメンバを定義して
それの初期化の中で実行させてみては?
// human.h
class Human() {
// 中略
class Initializer { Initializer() { onlyOnceCalled(); } };
static Initializer init;
};
// human.cpp
Human::Initializer Human::init;
文法間違ってたらすまん
276:275
08/03/25 02:51:47
Human::Initializerのコンストラクタがpublicになってないとか、いろいろダメだorz
そこは適当におぎなって
277:267
08/03/25 03:01:51
>>275
なるほど。こういう方法もあるんですね
勉強になりました
ありがとうございました
278:デフォルトの名無しさん
08/03/25 03:05:20
保証が欲しかったのか。失礼。
initialization orderを気にするならこんな感じかな。
class Human() {
class Initializer {
Initializer() { onlyOnceCalled(); }
public:
static void Initialize() { static Initializer instance; }
};
};
これで、Initializer::Initializeを呼んだタイミングで一度だけ初期化されるようになるよ。ただしこの場合は複数スレッドとかが動き出す前に呼んでね。
279:260
08/03/25 09:32:50
ぇ?コンパイル通る?
gccだと通らないんだけど・・・
280:デフォルトの名無しさん
08/03/25 09:53:30
>>279
どこを見てそう思うんだよ・・・
指摘してくれてるだろ
>>263
>>266
あとAcceptがReturnの返す一時オブジェクトを参照してるから何とかしよう
281:デフォルトの名無しさん
08/03/25 11:14:49
>>279
まずは省略や手抜きをせずに、Bの定義を全部書け。
そして何をしたいのかはっきりさせろ。
282:260
08/03/25 16:02:29
いや、やりたいことは下のやつを知りたかっただけ。
URLリンク(ja.wikibooks.org)(Move_Constructor)
に書いてあることってnon-const referenceを受けるべきとろこに一時オブジェクトを渡せるって話だと思って、
渡してみたらコンパイラ通らないどーん。な状況。
283:デフォルトの名無しさん
08/03/25 16:44:42
>>282
これで通った
struct B{
struct P{ B *temp; };
B(){}
B(P p){ swap( *this, *(p.temp) ); }
operator P () { P p; p.temp = this; return p; }
};
B Return(){ return B(); }
void Accept( B b ){};
int main(){ Accept( Return() ); }
284:デフォルトの名無しさん
08/03/25 17:14:20
参照渡しから値渡しに変更した理由が分からん
285:デフォルトの名無しさん
08/03/25 17:18:44
抽象クラスのメソッドの定義で質問があります
抽象クラスにおいて、自分自身のクラスへのポインタの引数を取るメソッドは不可能なのでしょうか?
たとえばこういうコードです
class Human {
void foo(Human *human) = 0;
};
コンパイルエラーになってしまいますが、なぜそうなるのか分かりません
抽象クラスだから、インスタンスを作れないので
void (Human human);
のようなメソッドはだめですよね、でもポインタならいけると思うのですが
286:デフォルトの名無しさん
08/03/25 17:20:52
B::operator P()の戻り値から構築されるBの一時オブジェクトは非const参照のAccept(B&)では受け取れないんじゃ?
287:デフォルトの名無しさん
08/03/25 17:23:26
その発送は無かったわ、thisポインタというものが(ry
virtual書いてみたらどうかな?
288:デフォルトの名無しさん
08/03/25 17:27:02
一時変数を値渡しする理由は?const参照にしない理由が分からない。
289:285
08/03/25 17:32:20
>>287
すいません元のコードではvirtualをつけてました
thisポインタは分かるのですが、この抽象クラスを継承したクラスの間でやりとりしたいことがあるのです
不勉強なので間違ってるかもしれませんが、「関連」というのをやりたいのです。
>>285の例でやるなら、一般的にはHumanクラスにHuman *hoge;みたいなポインタをメンバに持たせて関連付けするそうですが
関数の引数でやれないかと思いまして
290:デフォルトの名無しさん
08/03/25 17:35:09
>>288
const参照でもいいかもしれないけど、それ以上所有権を動かせなくならない?
291:デフォルトの名無しさん
08/03/25 17:45:20
Acceptに入ってからも譲渡するなら、
void Accept(B& b) {}
B b = Return();
Accept(b);
の方が良くないかな、それ以前に何のためのPなんだ?
292:デフォルトの名無しさん
08/03/25 17:47:47
>>285
どういう一般的例なのかちょっと分からないけど、
処理と情報を分ける実装の方が個人的にはスッキリするかな
んで、そのプログラムvirtualつけてエラーが出る理由が分からないんだけど…
293:デフォルトの名無しさん
08/03/25 17:49:24
あぁ、失礼した、operator Pはconst守るようにしてるのね
ごめん、俺が悪かった
294:292
08/03/25 18:06:34
>>292
すいませんすごく単純なクラスを作り直し、実験してみると、エラーはでませんでした。
「抽象クラスをインスタンス化することができません」というエラーメッセージだったので、
質問させていただいたのですが、おそらく他のところにエラー.の原因があると思うのでもう一度見直してみます
295:294
08/03/25 18:09:51
>>294の名前欄は>>285の間違いです
296:デフォルトの名無しさん
08/03/25 19:45:31
auto_ptrはauto_ptr_refクラスを介して対処している。
もう知っているかもしれないけど、
C++0xでは非const参照でも一時オブジェクトを受けられるようになる(右辺値参照)。
297:デフォルトの名無しさん
08/03/25 22:07:18
move semantics と rvalue reference &&
298:デフォルトの名無しさん
08/03/25 22:23:46
右辺値参照は何度もこのスレでも話されてるけど理解できん。
299:デフォルトの名無しさん
08/03/25 22:33:41
エラー出る出る言うなら、同じエラーが出る小さいプログラムを示せよ。
BやらPやらの例も、そもそもswapがないでコンパイル止まるしな。
300:デフォルトの名無しさん
08/03/25 22:34:02
右辺値及び左辺値(この二つは組)、参照の理解を固めてから見直すとよろし
301:デフォルトの名無しさん
08/03/25 22:45:08
>>298
簡単に言うと「swapでおk」ってこと。
次ページ最新レス表示スレッドの検索類似スレ一覧話題のニュースおまかせリスト▼オプションを表示暇つぶし2ch
4589日前に更新/200 KB
担当:undef