C言語関係掲示板

過去ログ

No.581.スタティックなメンバ関数

[戻る] [ホームページ]
No.5429

スタティックなメンバ関数
投稿者---麗(2003/03/04 09:12:54)


下の(1)、(2)のソースは文法上はともかく、同じ内容に思われます。
名前空間内の関数とスタティックなメンバ関数の違いや
それぞれの使い方を教えてください。

(1)
class piyo {
public:
  static void function();
};
main()
{
  piyo::function();
  return 0;
}

(2)
namespace piyo {
  void function();
}
main()
{
  piyo::function();
  return 0;
}


No.5430

Re:スタティックなメンバ関数
投稿者---すがり(2003/03/04 09:50:20)


>名前空間内の関数とスタティックなメンバ関数の違いや
>それぞれの使い方を教えてください。

使い方が変わる例としては…
(1)のクラススタティックなメンバ関数の場合は、絶対にpiyo::が必要なのに対して
(2)の名前空間は、using namespace piyo;としてしまえば、piyo::なしで呼べる
ってのはどうでしょう。

まあ、まともな話としては、(1)と(2)は使い方(=見た目)は同じでも、意味するところ
(=考え方)が違うでしょう。
クラスとは何らかの関連する機能や属性の集まりであり、クラスのメンバ関数とする
以上、その規則というか考え方に従うべきです。一方、名前空間は、クラスよりもっと
広いくくり方であり、直接的には関数名とかが衝突しないようにするための機構です。
例えば、自分の作ったライブラリ群全体を、一部に自分の名前を入れたような名前空間に
閉じ込めて、他のライブラリの同名の関数と衝突しないようにするなど。

No.5432

Re:スタティックなメンバ関数
投稿者---麗(2003/03/04 12:30:51)


> クラスとは何らかの関連する機能や属性の集まりであり、クラスのメンバ関数とする
> 以上、その規則というか考え方に従うべきです。

クラス内にスタティックなメンバ関数を持つといいこと(メリット)は何でしょうか?

privateなメンバ変数にアクセスできないので
名前空間で関数定義するのとあまり変わらないような気が…。

No.5433

Re:スタティックなメンバ関数
投稿者---すがり(2003/03/04 14:31:28)


>privateなメンバ変数にアクセスできないので

関連する機能や属性を集めるという話は、インスタンスがあるかどうかとは別の
次元の話だと思いますが、その辺、思い込みをしていませんか?
機能や属性は、各インスタンス固有(非static)のものもあれば、クラス固有(static)
のものもあるわけで、static、非staticに関係なく、関連する機能や属性ならば
1つのクラスにまとめて見通しをよくすることができるわけです。

privateな"非staticメンバ変数"にはアクセスできませんが、privateな"static
メンバ変数"にはアクセスできます。全てのメンバ変数やメンバ関数がstaticで
あるようなクラスも存在します。
ですが、関連する機能や属性をまとめたものであるということに変わりはありません。

> クラス内にスタティックなメンバ関数を持つといいこと(メリット)は何でしょうか?

よって、メリットも何も、クラスに固有な属性や機能を扱う必要があるならば、
クラスstaticにするというだけです。

>名前空間で関数定義するのとあまり変わらないような気が…。

前の発言でも言いましたが、変わらないのは"見た目"であって、根本に流れる
"思想"が違います。
もう少し言うと、誰かが書いたソースを読む際、あるクラスにまとまったものは
何らかの観点で集められたものなんだろうと推測できますが、ある名前空間の
直下に存在する各関数の場合は、一般には集められたものとは思わないため、
可読性が落ちてしまうでしょう。
## もしSTLがわかるならば、namespace std を考えてみて下さい。
## stdの中には、IO、各種データ構造、アルゴリズムなど、多数のクラスが存在します。

No.5435

Re:スタティックなメンバ関数
投稿者---麗(2003/03/04 17:30:38)


> privateな"非staticメンバ変数"にはアクセスできませんが、privateな"static
> メンバ変数"にはアクセスできます。全てのメンバ変数やメンバ関数がstaticで
> あるようなクラスも存在します。

スミマセン…。下のソースでリンクエラーが発生するので
privateでstaticなメンバ変数にアクセスできないと思っていました。
…ソースのどこかがおかしいのでしょうか?

エラーメッセージは
gcc2.95.4だと
/tmp/ccrgV81a.o: In function `piyo::func(void)':
/tmp/ccrgV81a.o(.text+0xb): undefined reference to `piyo::str'
*** Error code 1

gcc3.1.1だと
/var/tmp//cc4lx3Zw.o: In function `piyo::func()':
/var/tmp//cc4lx3Zw.o(.text+0x13): undefined reference to `piyo::str'
collect2: ld returned 1 exit status
…となります。

#include <iostream>

class piyo {
public:
  piyo(){ str = "Hello!!"; }
  static void func();
private:
  static char* str;
};

void
piyo::func()
{
  std::cout << str << std::endl;
}

main(void)
{
  piyo::func();
}


No.5437

Re:スタティックなメンバ関数
投稿者---すがり(2003/03/04 19:16:20)


これはC++に慣れていない人が陥りやすい誤りです。
staticなメンバ変数は、クラス定義の外に"定義"を書く必要があります。
これを書かないと、staticなメンバ変数は実体が確保されないため、麗さんが
書かれたようなリンクエラーになります。修正を下に載せます。
#include <iostream>

class piyo {
public:
//  piyo(){ str = "Hello!!"; } <=== 削除
  static void func();
private:
  static char* str;
};

char * piyo::str = "Hello!!"; <=== staticメンバ変数の"定義"(同時に初期化も)

void
piyo::func()
{
  std::cout << str << std::endl;
}

main(void)
{
  piyo::func();
}
長くなりますが、考え方を書きます。(正確かどうか自信がないですが…)

まず、非staticなメンバ変数の場合は、各インスタンス毎に1つずつ領域が確保
されます。よって、クラス"定義"の中に int a; と"宣言"するだけで、実際に
インスタンスが作られる際に自動的にaの領域も(インスタンスの一部として)
確保されます。
ここまでは、意識しなくてもできてしまう部分です。

ところが、staticなメンバ変数の場合は、クラスに対して1つだけ確保される
ものです。しかも、確保されるタイミングは、インスタンスの生成とは無関係で
実行時の最初(global変数と同じ)です。
そのため、クラス定義の中に static int a; と"宣言"を書いただけでは、実体
が確保されません。宣言に加えて、クラス定義の外に"定義"を書いて、初めて
メモリ内に実体が確保されます。
つまり、メンバ関数の"定義"と同じです。メンバ関数も各インスタンス内に関数
の実体(=マシン語の列)があるわけじゃなくて、実行時の最初に1つだけ確保
されるはずですよね。

No.5457

了解しました。
投稿者---麗(2003/03/05 08:38:49)


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

>これはC++に慣れていない人が陥りやすい誤りです。

はい。仰せのとおり慣れてません(苦笑)。

>つまり、メンバ関数の"定義"と同じです。メンバ関数も各インスタンス内に関数
>の実体(=マシン語の列)があるわけじゃなくて、実行時の最初に1つだけ確保
>されるはずですよね。

なるほど。理解しました。
Cの構造体にはない感覚ですね。
試しにCで構造体のメンバにstaticをつけてみたのですが
syntax errorではじかれました。

生意気な物言いで申し訳ありませんでした。
あと、御回答ありがとうございました。

No.5434

Re:スタティックなメンバ関数
投稿者---かずま(2003/03/04 15:12:06)


> クラス内にスタティックなメンバ関数を持つといいこと(メリット)は何でしょうか?

デザインパターンにシングルトンというのがあって、これはインスタンスを
1個しか作れないクラスです。

どうやって、実現するかというと、まず、コンストラクタを private にします。
コンストラクタが public だと、インスタンスが何個でも作れてしまうからです。
これで、クラスの外側からは、インスタンスを 1個も作れなくなってしまいました。

そこで、static なメンバ関数が必要になります。
メンバ関数からは、private なコンストラクタを呼べます。そのメンバ関数を
呼ぶ前には、まだインスタンスがないので、そのメンバ関数は static でないと
いけません。

No.5436

了解しました。
投稿者---麗(2003/03/04 17:40:13)


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

デザインパターンにはまだ手をつけてませんが
これを機に少し眺めてみます。
# その前にC++を勉強する必要が…。

ありがとうございました。