C++なのですが、複数のクラスで共通して使いたい関数がある場合、親クラスに共通したい
メンバ関数を作り、その子として複数のクラスを作るのが良いのでしょうか?
それ以外の方法だとクラスの外でstatic宣言した関数であればクラス内で使えるようでした。
(static宣言しないとコンパイルエラーとなりました)
しかし以下のサイトにあるように「共通関数継承のデメリット」があるようで推奨していないようです。
ttp://d.hatena.ne.jp/katzchang/20110216/p1
ttp://blog.jnito.com/entry/20110217/1297896355
なお、自分には上記サイトの内容は難しくて理解できませんでした。
つまり、「数のクラスで共通して使いたい関数がある」場合、上記サイトはどうすればいいと言っているのでしょうか?
よろしくお願い致します。
No.10
- 回答日時:
一部訂正です。
入れ子クラスの話ではなく、「自分が使う関数をクラスのメンバ関数として作ってしまった」ということでしたか。
No.10 の説明はほぼ、そのままで良いですが、ようするに、static をつけるとかつけないとかではなくて、「そのクラスの情報に直接アクセスする必要のない関数をクラスのメンバ関数にするな」ということだけです。
No.10 でも書きましたが、おそらくそれらの関数を、クラスの外に出すだけで話は終わるでしょう。
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);
}
などとすればいいです。
No.8
- 回答日時:
本題は, よ~するにあんたが「クラスの中で宣言している」って指摘してるだけじゃね? あんたがどのような意図でそうしてるかは知らんし, 「その親クラスを~」は「プログラムとして」どうすべきかもこんな文章でわかろうはずもない.
#3 への「お礼」のところについては, その ClassA::func を
・どのように呼び出しているのか
・どのように宣言しているのか
がわかればなんとかなるかもしれん.
No.6
- 回答日時:
static をつけた関数は、「静的」という名称ではありますが、いわゆる「静的変数」とは別の概念です。
・クラスの外の static 関数
グローバルな static な関数は、ファイルスコープを持たせるためのものです。
通常、グローバルな関数は、暗黙の内に、外部スコープを持ち、(いっしょにリンクした)他のファイルにあるソースからも呼び出すことができます。
しかし、グローバルな static 関数は、同じファイルからしかアクセスできません。
#include で読み込む部分に、この「グローバルなstatic関数の実体」があると、複数読み込まれ、それは別々のものと扱われます。
グローバルな static 変数も、同様に、ファイルスコープを持たせるために指定するものです。
・クラスの中の static 関数
クラスの中にある static な関数は、「静的メンバ関数」と呼ばれます。
通常クラスの中にある関数は、生成されたインスタンスに附属するものです(ちょっと違う)
一方、クラスの中にある static なメンバ関数は、クラス全体をとりまとめる(少なくとも、個々のインスタンスに縛られない)情報にアクセスするためのものです。
これは、(pubulic メンバなら)グローバルスコープを持ちます。
従って、include されるファイルに関数の実体があると、「一つしかないはずのもの」が複数存在することになり、(コンパイルではなく)リンクで失敗することがあります。
個々のインスタンスに縛られないという性質から、static 関数だけからなるクラスを作って、ツールボックスのように使うこともできます。
しかし、この用途であれば、クラスではなく、namespace によるグループ分けをおすすめします。
クラスの中にある static メンバ変数も同様で、クラス全体の情報(インスタンスの数とか)を持ちます。
・関数の中にある static な変数
これが、「自動変数」に対する「静的変数」です。
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つのプロジェクトを、複数人で開発し始めた時」にでも思い出せば良いです。
ありがとうございます。
>は、まったく異なる話。
そうですね…。読み返して改めて書き方がまずかったと思いました。
>「クラスの外で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 が見かけ上、ほぼ同じ用途に使えるでしょう)
親クラスで関数を定義して、それを、継承するというのは良い方法なのですが、「継承すべき」という状態でないと、途中で設計が破綻します。
設計が破綻した後でも、「継承」で乗り切ろうとすると、(それはつまり、本来やるべき事ではないことをやっているので)様々なデメリットが出てくるわけです。
ありがとうございます。
目的と使い方によってどう実装するかを変えるのですね…。
いちおう共有で使う関数はライブラリ化してあるインクルードファイルがあるのですが、
私が自作した関数はそこに入れることができず、自分のmain.cpp内でしか使わないので
どのように実装するのが良いのか、基準がぜんぜんわかりませんでした。
プログラマさんに聞いたところ、「継承でやるのではなくstaticを付けて宣言してください」とのことでした。
No.3
- 回答日時:
必要そうな回答は既についているのでいいとして……。
>(static宣言しないとコンパイルエラーとなりました)
エラーメッセージをそのまま掲示した方がよいでしょう。
変な意訳とかは不要です。
ありがとうございます。
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 …
| クラスライブラリは森にならず林にすべきだ
オブジェクト指向でプログラムを書くときは Liskov substitution principle を満たさない継承は怪しいとちょっと立ち止まって考えるというのがよいでしょうね。
http://ja.wikipedia.org/wiki/%E3%83%AA%E3%82%B9% …
あと、ここは2chではないので普通にURLを書いてくださいね。
ありがとうございます。
>クラスなどは使わず普通の関数として実装し、各クラスからはそれを単なる関数として呼ぶと良いでしょう。あるいは、その手の関数を集めたユーティリティクラスを作り、それを呼ぶかでしょう。
大規模プロジェクトの一部を担っているのですが、関数を集めたライブラリはあります。
しかし私が自分で使うだけの関数はそこに追加できないことになっています。
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を書いてくださいね。
すみませんでした。勝手に他サイトをリンクするとそのサイト運営者に迷惑かなと思ったので…。
以後気をつけます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
準・究極の選択
「年収1000万円で一生カレーライス」か 「年収180万円で毎日何でも食べ放題」 あなたはどちらを選びますか?
-
フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
あなたが普段思っている「これまだ誰も言ってなかったけど共感されるだろうな」というあるあるを教えてください
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
海外旅行から帰ってきたら、まず何を食べる?
帰国して1番食べたくなるもの、食べたくなるだろうなと思うもの、皆さんはありますか?
-
天使と悪魔選手権
悪魔がこんなささやきをしていたら、天使のあなたはなんと言って止めますか?
-
c++,ある関数のクラスから別のクラスの関数を呼ぶ
C言語・C++・C#
-
コンボボックスのドロップダウンリストが表示されない
C言語・C++・C#
-
1 つのヘッダファイルに複数のクラスって?
C言語・C++・C#
-
-
4
既定のコンストラクタがありません。というエラーについて
C言語・C++・C#
-
5
sys/time.hのインクルードができない
C言語・C++・C#
-
6
外部依存関係について
C言語・C++・C#
-
7
String^の^自体が何を意味しているのか、わかりません。
C言語・C++・C#
-
8
【VS2008 C++】2つのプロジェクト間で共通の関数を使いたい
C言語・C++・C#
-
9
共通で使う関数を集めたクラスについて
C言語・C++・C#
-
10
C++17で、unsigned char * 配列を、文字列リテラルで初期化する方法はありませんか?
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
河合塾のクラス分けについて
-
同じクラスにならない確率を教...
-
シングルページでのカレント表...
-
ATLとMFCの違いは何でしょうか?
-
IPアドレスの3バイト目の呼び方
-
クラスモジュールの使い方が詳...
-
現在または将来、需要のある言...
-
A・B・Cクラスとは?
-
オブジェクト間の依存性とは
-
IPアドレスのクラスAを取得して...
-
eclipse でクラスに色
-
DIVの中の<a>について
-
FunkctionとMethodの違いについ...
-
成人式の後中3のクラスで集まろ...
-
進学校通ってたんですけど、眼...
-
3年間同じクラスになる確率
-
重複エラーを解決するには
-
無名インナークラスからアクセ...
-
「天声人語」をインターネット...
-
JSP jsp:usebean で総称型クラ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
配列の重複する値とその個数を...
-
どこからも呼ばれていない無意...
-
java eclipse 型に解決できません
-
「天声人語」をインターネット...
-
main()を持つクラスが2つ以上...
-
1 つのヘッダファイルに複数の...
-
IPアドレスのクラスAを取得して...
-
同一パッケージにあるクラスが...
-
同じクラスにならない確率を教...
-
重複エラーを解決するには
-
共通で使う関数を集めたクラス...
-
3年間同じクラスになる確率
-
複数のクラスで共通した関数を...
-
同じパッケージ、クラス名が含...
-
A・B・Cクラスとは?
-
自作のクラスファイルがインポ...
-
ATLとMFCの違いは何でしょうか?
-
eclipse でクラスに色
-
コンボボックスのマウスホイー...
-
UMLのクラス図はmain()も含むん...
おすすめ情報