複数のクラスで共通したい関数を使う方法は?

このQ&Aのポイント
  • クラスの親クラスに共通したいメンバ関数を作る方法と、static宣言した関数を使う方法があります。
  • 親クラスに共通したいメンバ関数を作る方法では、複数のクラスを作って継承する必要があります。
  • しかし、共通関数継承にはデメリットもあり、static宣言した関数を使う方法も一考する必要があります。
回答を見る
  • ベストアンサー

複数のクラスで共通した関数を使いたい場合

C++なのですが、複数のクラスで共通して使いたい関数がある場合、親クラスに共通したい メンバ関数を作り、その子として複数のクラスを作るのが良いのでしょうか? それ以外の方法だとクラスの外でstatic宣言した関数であればクラス内で使えるようでした。 (static宣言しないとコンパイルエラーとなりました) しかし以下のサイトにあるように「共通関数継承のデメリット」があるようで推奨していないようです。 ttp://d.hatena.ne.jp/katzchang/20110216/p1 ttp://blog.jnito.com/entry/20110217/1297896355 なお、自分には上記サイトの内容は難しくて理解できませんでした。 つまり、「数のクラスで共通して使いたい関数がある」場合、上記サイトはどうすればいいと言っているのでしょうか? よろしくお願い致します。

  • suffre
  • お礼率76% (2013/2633)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.9

C++で「入れ子クラス(クラスの中に別のクラスを作ること)」は、可能ですが、私は使ったことがないです。 で、static の有無と、「クラスの中にクラスを作ったから」というのは、直接的な意味では関係ないです。 クラスの中にある(static でない)関数は、「メンバ関数」と呼ばれます。 これは、「クラスによって生成されたインスタンス」にバインドされた関数です。 例えば、 class A() { void a(); }; という場合、 A val; と、インスタンス(ここでは、val)を定義して、 val.a(); というけいろでしか呼び出すことはできません。 これは、val という「インスタンスに対して」何かせよといっているので、インスタンスが指定されないと「誰に?」ということになります。 だから、「別のクラスから呼び出している」つもりで、A::a() という呼び出しはできないわけです。 一方、static メンバ関数は、インスタンスにバインドされない関数です。 class A() { static b(); }; という場合、(アクセう制御が間違ってなければ) A::b() という呼び出しができます。 ただし、文法上は可能ですが、本来は、class A のことを司る関数であるべき(A のメンバですから)で、Aと関係なく関数を集めるという用途で使用するべきではありまん。 本当に、「自分だけが使う」関数であれば、それが小さなものなら、main と同じファイルの中で、単純に書けば済むことです。 main.cpp ---------------- int my_func_add(int a, int b) { int wk = a + b; return wk; } int my_func_sub(int a, int b) { int wk = a - b; return wk; } int main() { // いろいろな処理 int c = my_func_add(1, 2); int d = my_func_sub(c, 2); } こんな感じ。 もう少し増えれば、 my_fun.h というファイルに int my_func_add(int a, int b); int my_func_sub(int a, int b); として、 my_func.cpp に実体を書いて #include "my_func.h" int my_func_add(int a, int b) { int wk = a + b; return wk; } int my_func_sub(int a, int b) { int wk = a - b; return wk; } main.cpp で #include "my_func.h" int main() { // いろいろな処理 int c = my_func_add(1, 2); int d = my_func_sub(c, 2); } などとすればいいです。

その他の回答 (10)

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.11

もしかして class A { #include "inline.inl" }; のような事をしてるって事なのでしょうか。

回答No.10

一部訂正です。 入れ子クラスの話ではなく、「自分が使う関数をクラスのメンバ関数として作ってしまった」ということでしたか。 No.10 の説明はほぼ、そのままで良いですが、ようするに、static をつけるとかつけないとかではなくて、「そのクラスの情報に直接アクセスする必要のない関数をクラスのメンバ関数にするな」ということだけです。 No.10 でも書きましたが、おそらくそれらの関数を、クラスの外に出すだけで話は終わるでしょう。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

本題は, よ~するにあんたが「クラスの中で宣言している」って指摘してるだけじゃね? あんたがどのような意図でそうしてるかは知らんし, 「その親クラスを~」は「プログラムとして」どうすべきかもこんな文章でわかろうはずもない. #3 への「お礼」のところについては, その ClassA::func を ・どのように呼び出しているのか ・どのように宣言しているのか がわかればなんとかなるかもしれん.

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.7

質問とは直接関係ありませんが staticな関数であることと、その関数がスレッドセーフであるかどうかは無関係なので勘違いしないでくださいね。

回答No.6

static をつけた関数は、「静的」という名称ではありますが、いわゆる「静的変数」とは別の概念です。 ・クラスの外の static 関数 グローバルな static な関数は、ファイルスコープを持たせるためのものです。 通常、グローバルな関数は、暗黙の内に、外部スコープを持ち、(いっしょにリンクした)他のファイルにあるソースからも呼び出すことができます。 しかし、グローバルな static 関数は、同じファイルからしかアクセスできません。 #include で読み込む部分に、この「グローバルなstatic関数の実体」があると、複数読み込まれ、それは別々のものと扱われます。 グローバルな static 変数も、同様に、ファイルスコープを持たせるために指定するものです。 ・クラスの中の static 関数 クラスの中にある static な関数は、「静的メンバ関数」と呼ばれます。 通常クラスの中にある関数は、生成されたインスタンスに附属するものです(ちょっと違う) 一方、クラスの中にある static なメンバ関数は、クラス全体をとりまとめる(少なくとも、個々のインスタンスに縛られない)情報にアクセスするためのものです。  これは、(pubulic メンバなら)グローバルスコープを持ちます。  従って、include されるファイルに関数の実体があると、「一つしかないはずのもの」が複数存在することになり、(コンパイルではなく)リンクで失敗することがあります。 個々のインスタンスに縛られないという性質から、static 関数だけからなるクラスを作って、ツールボックスのように使うこともできます。 しかし、この用途であれば、クラスではなく、namespace によるグループ分けをおすすめします。 クラスの中にある static メンバ変数も同様で、クラス全体の情報(インスタンスの数とか)を持ちます。 ・関数の中にある static な変数 これが、「自動変数」に対する「静的変数」です。

  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.5

>それ以外の方法だとクラスの外でstatic宣言した関数であればクラス内で使えるようでした。 と >しかし以下のサイトにあるように「共通関数継承のデメリット」があるようで は、まったく異なる話。 「クラスの外でstatic宣言した関数」は、言わば「静的に確保した変数」みたいなモノで、スレッドセーブではないので、論外。お話にならない。 一方 http://d.hatena.ne.jp/katzchang/20110216/p1 http://blog.jnito.com/entry/20110217/1297896355 (当サイトでは、URLを書いても問題ないので、2chのように「hを削る」なんて必要は無い。クリック出来ずに不便なので、こういう書き方はマナー違反になるので注意) のサイトは >親クラスに共通したいメンバ関数を作り、その子として複数のクラスを作る と言う場合の問題点について議論している。 Aが親で、その下にBとCのクラスがある場合、Bからの要求により、Aのメンバ関数の仕様を変えると、仕様変更を想定してないCのクラスでバグを生む可能性がある。 なので、こういう場合は「共通して使いたい関数だけが入ったクラス」を別に作って、Bが仕様変更を要求したら、クラスを継承した新クラスを作って、新クラスの方だけに仕様変更を盛り込む。 そうすると「仕様変更を想定してないC」は、継承元の「仕様変更の無いクラス」をそのまま使っていれば問題を起こさない。 「全部一人でコーディングしている」なら、こんな事は気にしないで、好きに書いていれば良いよ。 >上記サイトはどうすればいいと言っているのでしょうか? 上記のサイトで出てきた話って「複数人でコーディングしてて、グループ開発をしている時の話」だから、自分ひとりで全部書いてるなら、忘れても良い話。 質問者さんが「1つのプロジェクトを、複数人で開発し始めた時」にでも思い出せば良いです。

suffre
質問者

お礼

ありがとうございます。 >は、まったく異なる話。 そうですね…。読み返して改めて書き方がまずかったと思いました。 >「クラスの外でstatic宣言した関数」は、言わば「静的に確保した変数」みたいなモノで、スレッドセーブではないので、論外。お話にならない。 この質問を書いた後に一緒に仕事をしているプログラマさんに聞いたところ、私が記述しているコードは 全て「あるクラスの中」なのだそうです。 inline.inlとmain.cppに分かれていて、inline.inlに関数やクラスを宣言し、main.cppに実体を書いて、実装もしています。 このinline.inlとmain.cppが「あるクラスの中」だと言っていました。 ※No.1~4さんの回答に「インクルードファイル」と書きましたが「inline.inl」というファイルでした。実際のファイル名は「inline」ではなくプロジェクト名に関する名前ですが拡張子はinlです。 間違ってすみませんでした。 >なので、こういう場合は「共通して使いたい関数だけが入ったクラス」を別に作って、Bが仕様変更を要求したら、クラスを継承した新クラスを作って、新クラスの方だけに仕様変更を盛り込む。 そういうことなのですね。よくわかりました。 >「全部一人でコーディングしている」なら、こんな事は気にしないで、好きに書いていれば良いよ。 かなり大規模なプロジェクトで担当しているのですが、自分が触っている部分に関しては私しかコーディングしないです。他のプログラマさんが見ることもほとんどないです。

回答No.4

この場合、「複数のクラス」がどういうものなのかが問題です。 単に、(本質的に関係ない)いろいろなクラスで使い回したい便利な関数を集めるのであれば、既に回答があるように、通常の関数として定義すれば良いでしょう。 それらの「いろいろな関数」自体がある程度の共通性を持つなら、namespace という機能でグループ分けすることもできます。 逆に、「複数のクラス」というのが、「実は(もともと継承できるほど)共通性のあるもの」であれば、「元々共通的なクラス」に使うための(逆に言えば、他のクラス群では使わないだろうと思われる)関数(やデータメンバ)を含んだ、抽象クラスを作って、それを継承するというのは、間違いではありません。 ※ただ単に、「便利そうな関数をまとめておきたい」という理由なら、クラスを使うべきではありません(が、namespace が見かけ上、ほぼ同じ用途に使えるでしょう) 親クラスで関数を定義して、それを、継承するというのは良い方法なのですが、「継承すべき」という状態でないと、途中で設計が破綻します。 設計が破綻した後でも、「継承」で乗り切ろうとすると、(それはつまり、本来やるべき事ではないことをやっているので)様々なデメリットが出てくるわけです。

suffre
質問者

お礼

ありがとうございます。 目的と使い方によってどう実装するかを変えるのですね…。 いちおう共有で使う関数はライブラリ化してあるインクルードファイルがあるのですが、 私が自作した関数はそこに入れることができず、自分のmain.cpp内でしか使わないので どのように実装するのが良いのか、基準がぜんぜんわかりませんでした。 プログラマさんに聞いたところ、「継承でやるのではなくstaticを付けて宣言してください」とのことでした。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

必要そうな回答は既についているのでいいとして……。 >(static宣言しないとコンパイルエラーとなりました) エラーメッセージをそのまま掲示した方がよいでしょう。 変な意訳とかは不要です。

suffre
質問者

お礼

ありがとうございます。 No.1さんの回答に付け加えて、エラーメッセージは以下のような感じでした。 main.cpp:error C2352 'ClassA::func':静的でないメンバー関数の呼び出しが正しくありません。 inline.inl:'ClassA::func'の宣言を確認してください。

回答No.2

> C++なのですが、複数のクラスで共通して使いたい関数がある場合、親クラスに共通したい メンバ関数を作り、その子として複数のクラスを作るのが良いのでしょうか? いいえ。 クラスなどは使わず普通の関数として実装し、各クラスからはそれを単なる関数として呼ぶと良いでしょう。あるいは、その手の関数を集めたユーティリティクラスを作り、それを呼ぶかでしょう。 > それ以外の方法だとクラスの外でstatic宣言した関数であればクラス内で使えるようでした。 > (static宣言しないとコンパイルエラーとなりました) それはもしかして、ヘッダーファイルに関数の実体まで書いてしまっているから? プロトタイプ宣言だけをヘッダーファイルに書いておき、実体をあとでリンクするようにしていたらそういうことは起きないと思いますが。 > つまり、「数のクラスで共通して使いたい関数がある」場合、上記サイトはどうすればいいと言っているのでしょうか? 上記サイトをざっと読んだ限り、サイト自身にデメリットは書いてありますが、だからどうしたらよいかというのは書いてないようです。そのリンク先では、ユーティリティクラスとして実装することを推奨しているように見えますが。 http://en.wikipedia.org/wiki/Constant_interface | Many of the pitfalls of the anti-pattern can be avoided by converting the constants interface to a proper class with no instances http://blogs.itmedia.co.jp/hiranabe/2005/12/pojo_dcce.html | クラスライブラリは森にならず林にすべきだ オブジェクト指向でプログラムを書くときは Liskov substitution principle を満たさない継承は怪しいとちょっと立ち止まって考えるというのがよいでしょうね。 http://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%B9%E3%82%B3%E3%83%95%E3%81%AE%E7%BD%AE%E6%8F%9B%E5%8E%9F%E5%89%87 あと、ここは2chではないので普通にURLを書いてくださいね。

suffre
質問者

お礼

ありがとうございます。 >クラスなどは使わず普通の関数として実装し、各クラスからはそれを単なる関数として呼ぶと良いでしょう。あるいは、その手の関数を集めたユーティリティクラスを作り、それを呼ぶかでしょう。 大規模プロジェクトの一部を担っているのですが、関数を集めたライブラリはあります。 しかし私が自分で使うだけの関数はそこに追加できないことになっています。 No1さんの答えにも書きましたが、ClassAの中に関数を作っていたようでした。 なのでstaticを付けないとClassAの中で作ったClassB, ClassCでは使えないみたいです。 プログラマさんは、「ClassAの中にClassB, ClassCがあるのだけど、別クラスなのでfuncAはstaticを付けないと ClassB, ClassCの中では使えないんです」と言っていました。 すみませんがなぜstaticを付けるべきなのか、もう少し詳しく教えていただけますか? >それはもしかして、ヘッダーファイルに関数の実体まで書いてしまっているから? >プロトタイプ宣言だけをヘッダーファイルに書いておき、実体をあとでリンクするようにしていたらそういうことは起きないと思いますが。 よくわかりませんが、インクルードファイルにfuncA, ClassB, ClassCを宣言し、main.cppで実体を書いています。 このインクルードファイルとmain.cppがどうリンクされているのかは複雑でよくわかりませんでした。 >オブジェクト指向でプログラムを書くときは Liskov substitution principle を満たさない継承は怪しいとちょっと立ち止まって考えるというのがよいでしょうね。 急に大規模プロジェクトの一部を任されて、C++は初めてまだ1ヶ月ほどなのでオブジェクト指向というものがまだまだわかっていません。 プロジェクトの構造も複雑で、プログラマさんに解説していただいてもかなりちんぷんかんぷんです…。 >あと、ここは2chではないので普通にURLを書いてくださいね。 すみませんでした。勝手に他サイトをリンクするとそのサイト運営者に迷惑かなと思ったので…。 以後気をつけます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

え~と.... 「static宣言しないとコンパイルエラーとなりました」って, どういうことでしょうか? そんなことはありえないのですが....

suffre
質問者

お礼

ありがとうございます。 大規模プロジェクトの中の一部分のコードを担当しています。 私はプログラマではないのですが事情によりプログラミングしています。 ちなみにプログラマの方に聞いたところ、 「あなたが関数を宣言している部分は、実はクラスの中なのです」 「その親クラスを例えばClassAとして、ClassAの中に関数funcAを宣言し、同じくそのClassAの中に 複数の子クラス(例えばClassB, ClassC)を宣言した場合、ClassB, ClassCでfuncAを使いたい 場合にはstaticを付けて宣言しないと使えないんです」 とのことでした。

関連するQ&A

  • 複数クラスで共通の関数、変数の呼び出し方

    お世話になります。 質問させて頂きたいことは 複数のクラスで共通して使われる関数、変数があった場合、その関数、変数は私の中で次の2通りの方法が思い当たったのですがどちらのほうがメモリ等の使用からよいのでしょうか? 1つめは あるヘッダファイル****.hを作成し、その中で関数を宣言し、変数はそのヘッダファイルのソースファイル中のグローバル変数とする。 2つめは クラスを作成し、静的メンバ関数、静的メンバ変数とする。 ネット等で拝見すると、あまりグローバル変数というのはよく見られていないようなので2つめの方がいいのかなと思っているのですが、静的メンバを今まで使ったことがないので、このような用途に使われるべきなのかも正直わかっていません。 検討外れのことを言っているのかもしれませんが、教えて頂ければと思っております。宜しくお願い致します。

  • クラスのメンバ関数を別ファイルで定義したときのバグ

    C++ においてヘッダファイルで宣言したクラスのメンバ関数を別のソースファイルで定義して、コンパイルするとうまくいきません。エラーは出ないのですが、同名の何もしない関数としてコンパイルされているようなのです。クラスのメンバ関数を宣言したのと同じヘッダに書くとちゃんとコンパイルされます。 どうしてそうなるのか、いまいち原因がわかりません。

  • static変数を持ったクラスを継承した複数のクラスで、独立してその変

    static変数を持ったクラスを継承した複数のクラスで、独立してその変数を使いたい。 例えば、 class AbstractStatic{ public static String str; } class Ex1 extends AbstractStatic{} class Ex2 extends AbstractStatic{} というクラスがあったとして、 Ex1 e1 = new Ex1(); ex1.str = "hoge"; といれると、 ex2.str で、hogeが入ってしまいます。同じようなstatic変数を持つクラスを複数作りたいのですが、継承させると、独立して変数を持たせられません。 同じようなクラスに直接static変数を、記述するしかないのでしょうか?

    • ベストアンサー
    • Java
  • C++のクラス設計について

    Webや書籍をあたってみたのですが、なかなか解決しないので こちらで相談させいただこうと思い立ちました。 C++で書かれたプログラムを解析しているのですが、 ドキュメントは外部仕様書のみであとはソースコードだけ、という状態です。 コメントもほとんど書かれていないコードについて、リバースエンジニアリングを する必要があり、手始めにクラス図を作成してみました。 すると、複数のクラスでメンバ変数が重複しているのです。 クラスAに、クラスB・C・Dの変数の一部が宣言されていて、 クラスAとクラスBの間で重複している変数はすべてどちらのクラスもprotectedのstatic、 クラスAとクラスC・Dの間で重複している変数はクラスAではprotectedのstatic、 C・Dではprivateです。 クラスBとC・Dは継承関係にありますが、メンバ変数の重複はありません。 クラスAと他クラスは継承関係がなく、メンバ変数が多数重複しています。 クラスAの変数は20個ほどありますが、9割以上がB・C・Dで宣言されている変数と 重複している状態で、かつstaticのprotectedです。 Cはわかるのですが、C++はほとんど書いたことがありません。 アンチパターンなどもあたってみたのですが、上記のような設計についての記述は 見つけられませんでした。こういったクラス間での変数重複は「あり」なのでしょうか? これで情報が足りているかわかりませんが、何卒よろしくお願い致します。

  • 「static宣言されているメンバ関数」は、「インスタンスメソッド」な

    「static宣言されているメンバ関数」は、「インスタンスメソッド」なのでしょうか? それとも、「クラスメソッド」なのでしょうか? 先日、下記内容で質問して、その時は分かったつもりだったのですが、 やっぱり分かってなかったようなので、教えてください。 ▽「クラス関数」「メンバ関数」「メソッド」の違いを教えてください。   http://okwave.jp/qa/q5858806.html 例) ▽前提 ・Aクラスのインスタンスa ・static宣言されたpublicメソッド「static_public_method」 ・static宣言されていないpublicメソッド「public_method」 ▽メンバ関数呼び出し ・$a->static_public_method() ・A::static_public_method() ・A::public_method() このとき、「$a->static_public_method()」は、インスタンス経由でアクセスすることになるので、 「インスタンスメソッド」になるのでしょうか。それとも、static(静的)宣言しているので、「クラスメソッド」になるのでしょうか? また、「A::static_public_method()」や、「A::public_method()」は、どちらになるのでしょうか? ※現在、頭の中がこんがらがっているのは、下記3点です。どれかひとつでも構わないので、分かりやすい考え方等あれば、ぜひ教えてください。 ・「static宣言したメンバ関数」は、「インスタンスメソッド」? 「クラスメソッド」? ・「スタティック」宣言してるのに、メンバ関数へ、「->(アロー演算子)」(オブジェクト経由)でアクセスできる理由 ・「A::static_public_method()」と「A::public_method()」の違い

    • ベストアンサー
    • PHP
  • クラスのメンバ関数が多すぎる場合のデメリットはありますか?

    クラスのメンバ関数が多すぎる場合のデメリットはありますか? C++ であるクラスを実装してメンバ関数の追加を続けていたところ、メンバ関数の数が数十にまでふくれあがってしまいました。 このようにクラスのメンバ関数の数が多くなってしまった場合、パフォーマンス上でデメリットがありますでしょうか。 私としては、メンバ関数分だけメモリを食う、クラスのコピーが遅くなる、といいた点で心配なのですが実際のところどうなのでしょうか? (メンバ関数は、基本的にはクラスのメンバを操作するものなので、グローバル関数ではなくてクラスのメンバにしておいたほうが分かりやすいかなと思っています。)

  • 共通関数をどうするべきか

    複数の場面で共通の関数を使っていました。 EXCELなどのVBの共通関数は、VB2010ではmoduleに置けば 同じになることが分かりましたが、批判もあるようです。 取り敢えず、次の3つに絞りこみましたが、どれが適当でしょうか。 1 moduleに記述してどこでも自由に呼び出せるようにすべき 2 common等のクラスを作って、そこにまとめて置く 3 あくまで関連するクラスに付属させるべき。重複は仕方ない。 4 その他(理由をお願いします)

  • C++ クラス概念

    以下の違いがよく理解できていません。 どなたかご教授お願い致します。 (1)クラスのメンバー変数に static を付けた場合と、 メンバーではない変数に static を付けた場合の違い (2)クラスのメンバー関数に static を付けた場合と、 メンバーではない関数に static を付けた場合の違い [プログラム例] class MyClass { public: static int internalCount; static void func(MyClass& a) {/* ... */} }; static int i; static void f(MyClass& a) { /* ... */ }

  • 「クラス関数」「メンバ関数」「メソッド」の違いを教えてください。

    「クラス関数」「メンバ関数」「メソッド」の違いを教えてください。 あるサイトに、「クラス関数」=「メンバ関数」と書かれていました。 「メンバ関数」=「メソッド」だと思っているのですが、 そうすると、「クラス関数」=「メンバ関数」=「メソッド」という認識で間違いないでしょうか?

    • ベストアンサー
    • PHP
  • 基本クラスのポインタで、派生クラスのメンバ関数を呼び出す方法?

    VC++でプログラミングをしています。 A(基本クラス) B(派生クラス) を作成しました。Bは、Aの特別な場合です。 このとき、基本クラスAのポインタから、派生クラスBにのみあるメンバ関数を呼ぶことはできないのでしょうか? 基本クラスAにも同じ名前の関数があれば、仮想関数をオーバーロードすれば呼び出せるようですが、この関数は、基本クラスには不要なので、できれば使わないメンバ関数を基本クラスに書きたくありません。 (純粋仮想関数という方法もあるようですが、) 操作としましては、 Aのポインタ配列 A* a[100]を作成し 特別な場合のみ派生クラスBのメンバ関数だけを実行させたいのです。 派生クラスにのみあるメンバ関数を、Readとします。 for(i=0;i<100;i++){ if(派生クラスBの場合){ a[i]->Read() } } 現状では、コンパイルエラーで、 関数Readは、aのメンバ関数ではありませんとなってしまいます。 以上よろしくお願いします。