C++相談室 part26

このエントリーをはてなブックマークに追加
>>780
それでstaticな下駄雪駄を作ると。
そういう話じゃないわけだが。
静的メンバ変数は静的メンバ関数だけからアクセスする
癖を付けるのもいいかも。事実Singletonのデザインでは
そのようにしている。

但し複雑さというのは避けられないもので、静的メンバ変数
が他の箇所からほぼ同時にアクセスされる環境、すなわち
マルチスレッド環境では何らかの同期が必要となる。
784776:04/01/15 01:15
>>778
そのとおりです

>>779
その理由でしたらClass::Staticsだけでアクセスすればよいと思うのです

>>780
そしたら外から見えないし・・・

結局のところ>>777の理由からでしょうかね?
>>784
外から見えるようにするってあーた、それじゃわざわざ
静的にしろメンバ変数にする意味ないじゃん。
786776:04/01/15 01:23
>>783
>静的メンバ変数は静的メンバ関数だけからアクセスする癖を付けるのもいいかも。
>事実Singletonのデザインではそのようにしている。
そうですね。静的メンバ変数はprivateにして、
静的メンバ変数にアクセスするpublicな関数を用意するわけですね
しかし今度はClass::StaticFunctions()だけではなく、
instance.StaticFunctions()でもアクセスできる
という問題が発生してしまいまして・・・

まあ、幾分かましではありますが。
結論を手短にまとめると、>>784さんは

・クラスの静的メンバ変数が欲しい
・しかしそれはインスタンスから参照できないようにして欲しい
・しかもClass::Staticsという形でアクセスできるようにして欲しい

って所かな。そしたら、基底クラスでprotected属性で宣言し、
それを継承したクラスでのみインスタンスを作成する、という
方法ではだめなのかいな。
あーprotectedにするとClass::Staticsという形ではアクセスでき
ないか。
staticメンバ関数でアクセス方法だけ制限してやりゃええ話なのでは
>>789
詰まる所そうなりますね。それ以上はC++を使う人の責任で、
って事で。
static メンバ関数に
インスタンスからアクセスできなくする法はちと無理。
static と非 static でオーバーロードもできないし。
ああ、int型に限っては一つだけ方法がある。
クラス内 enum 値はインスタンスから参照できなかったはずだ。
>>792
こういう事でなくて?どうやってアクセス禁止になるんだろう。

#include <iostream>

class A {
public:
 enum E {a, b, c};
};

int main()
{
 A a;
 std::cout << a.b << std::endl;
}
無名でもできなかったっけ……
すまん、じゃあ勘違いだ
それじゃこんなのはどうだろ?
コンストラクタを返り値のように受けるのは微妙な問題があるけど
見た目上は要求の物に近いんでない?
複数の異なった値が欲しければ int に関しては
template < int n > と typedef を組み合わせれば
簡単なフレームワークで出来るはずだ。

class A {
public:
struct value{
operator int() const {
return 0;
}
};
};

int main() {
int v = A::value();
A a;
v = a.value(); // ここでエラー
}
テストコード。一応、gcc3.2(MinGW)で動作確認済み。

#include <iostream>

class Integer {
public:
friend struct setValue {
explicit setValue(int n) { n_ = n; }
};
friend struct getValue {
operator int() const { return n_; }
};
private:
static int n_;
};

int Integer::n_ = 0;

int main(void) {
Integer::setValue(4);
std::cout << Integer::getValue() << std::endl;
Integer i;
//i.setValue(4);
//std::cout << i.getValue(4) << std::endl;
}
>>795>>796
クラスのメンバに変換演算子のみを持つとそれは
初期化の時しか参照できないんだね。初めて知った。
しかもそれは一時変数で、目的の変数に代入が終了
したら消滅する。よくできたもんだ。

しかし>>796は残念だな。VC7.1でコンパイルできない。

c:\Documents and Settings\**\My Documents\Visual Studio Projects\Conversion\Conversion.cpp(9) : error C2391: 'Integer::setValue' : 'friend' は型定義中には使えません。
c:\Documents and Settings\**\My Documents\Visual Studio Projects\Conversion\Conversion.cpp(12) : error C2391: 'Integer::getValue' : 'friend' は型定義中には使えません。
c:\Documents and Settings\**\My Documents\Visual Studio Projects\Conversion\Conversion.cpp(24) : fatal error C1903: 直前のエラーを修復できません。コンパイルを中止します。
>>797
エラーメッセージ読んだ感じ
定義後に friend 宣言すれば問題ないんとちゃう?
(それできなかったら多くの内部型が困りそうだ)
>>798
結果だけ書くと、VC7.1はfriend宣言取ってもコンパイルできた。
事後のfriend宣言でも通ったけど、gccと挙動が違う。
>>784の件についてだが
コンストラクタをprivateとかにしてインスタンスを生成できなくすればいいんでないの?
>>800
いや、インスタンスが生成できて、かつstaticなメンバ変数
にインスタンスからアクセス不可能にしたかったようです。
a.b とか pa->b という記法で static member変数を参照できる、
というのがキモチ悪かったっていうことだと思います。

漏れも少しキモチ悪い。virtual static member variable なんてのが
あるならともかく。
functionはともかくvariableはないだろw
>>802
気持ち悪いか。感覚の違いだな。
俺はそう書けて当然だと思う。統一が取れてて。
805デフォルトの名無しさん:04/01/15 21:32
質問です。intやcharで定義する変数名は英語ならどんな名前でもいいんですか?

int ten;
int x;

char name;
char a;

are you ok?
>>805
名前付けルールはそのコードを維持する人が良いと思えば
何語だってかまわんよ。使える文字を使ってさえいれば。
>>806
thank you
>>803
>functionはともかくvariableはないだろw

いや、こんな感じ。vtbl みたいなクラス毎の変数用ストレージ。
struct A {
 virtual static const int object_id = ID_A;
};

struct B : public A {
 virtual static const int object_id = ID_B;
};

A* pa = new B;
pa->object_id // ID_B になる
809超初心者:04/01/15 22:51
プログラミングの仕方が全然わからないんですが○×ゲームでかならず引き分けるプログラムをどのようにプログラミングしたらいいか教えていただけませんでしょうか。
「必ず引き分ける」なんて結果のみを期待されても答えられない。
その手の手数の少ない対戦ゲームなら
素直にMAX-MIN法を使ってゲーム木を探索して手を決定するとか。

>○×ゲーム
3*3の三目並べのこと?
ならウォー・ゲームでも繰り返し鑑賞しなさい
812デフォルトの名無しさん:04/01/15 23:58
おながいします。
テンプレートの引数にテンプレートを指定することはできないのですか?
CList<CArray<CPoint,CPoint>> m_list;
みたいな。。。
>>812
できます。
814812:04/01/16 00:10
レスありがとうございます。
VC++6.0なのですが
error C2146: 構文エラー : ',' が、識別子 'm_list' の前に必要です。
みたいなエラーが出てコンパイルできないのですが...
だまされないように。できません。
×:>>
○:> >
VC6ではテンプレートのネストはできない。
もっと新しいコンパイラを使え。
できるっつーの
819812:04/01/16 00:26
>>816
どうもありがとう(TT)
でも今度はリンクができなくなってしまったのですが・・・
820812:04/01/16 00:30
できました。
教えてくださったみなさんどうもありがとう。。。
821デフォルトの名無しさん:04/01/16 00:51
すみません。また812です。
別件なのですが、テンプレートクラスを含んだcppファイルを
コンパイルはできるのですが、それを使用したcppをコンパイルして
リンクしようとすると、シンボル未解決でリンクエラーになります。
何か考えられる原因はあるでしょうか?
>>821
エラーメッセージぐらい貼れよ
823921:04/01/16 01:00
>>822
すいません。m(__)m
通常のマングリングコードが出てシンボルは未解決ですって
いうエラーです。
というか今解決しました。hとcppにわけていたのですがhにまとめたら
うまくいきました。でもなんでなんでしょう???
あらゆるtemplateは定義までヘッダにおいとかないと
たいていのコンパイラで上手くリンクまでできない。
825921:04/01/16 01:02
そうなんですね。知りませんでした。。。
826821でした:04/01/16 01:05
遅くにどうもありがとう。。。
827デフォルトの名無しさん:04/01/16 01:21
class CObjAddr{};
class CPtrA{public: operator CObjAddr() const { return CObjAddr(); };
class CPtrB{public: operator CObjAddr() const { return CObjAddr(); };
bool operator== (const CObjAddr& lhs, const CObjAddr& rhs) { return true; }
int main()
{
CPtrA a;
CPtrB b;
if (a == b);
return 0;
}

はコンパイルできるのですが

template <typename T> class CObjAddr{};
template <typename T> class CPtrA{public: operator CObjAddr<T>() const { return CObjAddr<T>(); };
template <typename T> class CPtrB{public: operator CObjAddr<T>() const { return CObjAddr<T>(); };
template <typename T>
bool operator== (const CObjAddr<T>& lhs, const CObjAddr<T>& rhs) { return true; }
int main()
{
CPtrA<int> a;
CPtrB<int> b;
if (a == b);
return 0;
}

になると途端に==演算子を見つけられなくなります。
正確に言うと上の方のコードのoperator==にtemplate <typename T>と付けた時点(型名にはTがかかっていない状態)で
既に==演算子を見つけられなくなります。
下の状態で a == b をそのままの形で(明示的にキャストせずに)コンパイルできるようにしたいのですが
何か方法はないでしょうか?よろしくおねがいします。
エラーメッセージをよく読んで } の数を数えてみることを勧める。
つーか上のコードよく通ったな。
829827:04/01/16 03:54
>>828
ここに載せられるように簡略化したときにちょっと失敗しました。
class CObjAddr{};
class CPtrA{public: operator CObjAddr() const { return CObjAddr(); }};
class CPtrB{public: operator CObjAddr() const { return CObjAddr(); }};
bool operator== (const CObjAddr& lhs, const CObjAddr& rhs) { return true; }
int main()
{
CPtrA a;
CPtrB b;
if (a == b);
return 0;
}

template <typename T> class CObjAddr{};
template <typename T> class CPtrA{public: operator CObjAddr<T>() const { return CObjAddr<T>(); }};
template <typename T> class CPtrB{public: operator CObjAddr<T>() const { return CObjAddr<T>(); }};
template <typename T> bool operator== (const CObjAddr<T>& lhs, const CObjAddr<T>& rhs) { return true; }
int main()
{
CPtrA<int> a;
CPtrB<int> b;
if (a == b);
return 0;
}
ですね。質問の本質的内容は変わりません。よろしくお願いします。
たぶん暗黙の型変換とテンプレート引数の双方のマッチングが
絡み合って適用されないんだな。

キャストをしたくないのなら、
明示的にテンプレート引数を指定して実体化させるか、
別の関数を挟むかするしかないだろ。
template <typename T_>
class CPtrA
{
public:
  operator CObjAddr<T_>() const { return CObjAddr<T_>(); }

  bool operator==( const CObjAddr<T_>& rhs ) const {
    return true;
  }
};
にするとか・・・。めんどいかね・・・。