C++なのですが、複数のクラスで共通して使いたい関数がある場合、親クラスに共通したい
メンバ関数を作り、その子として複数のクラスを作るのが良いのでしょうか?
それ以外の方法だとクラスの外でstatic宣言した関数であればクラス内で使えるようでした。
(static宣言しないとコンパイルエラーとなりました)
しかし以下のサイトにあるように「共通関数継承のデメリット」があるようで推奨していないようです。
ttp://d.hatena.ne.jp/katzchang/20110216/p1
ttp://blog.jnito.com/entry/20110217/1297896355
なお、自分には上記サイトの内容は難しくて理解できませんでした。
つまり、「数のクラスで共通して使いたい関数がある」場合、上記サイトはどうすればいいと言っているのでしょうか?
よろしくお願い致します。
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.10
- 回答日時:
一部訂正です。
入れ子クラスの話ではなく、「自分が使う関数をクラスのメンバ関数として作ってしまった」ということでしたか。
No.10 の説明はほぼ、そのままで良いですが、ようするに、static をつけるとかつけないとかではなくて、「そのクラスの情報に直接アクセスする必要のない関数をクラスのメンバ関数にするな」ということだけです。
No.10 でも書きましたが、おそらくそれらの関数を、クラスの外に出すだけで話は終わるでしょう。
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で質問しましょう!
似たような質問が見つかりました
- JavaScript カラーミーショップのsectionループ内で、[引数][戻り値]ありの関数的な処理を行いたいです。 1 2022/05/07 19:39
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- Excel(エクセル) Excelで全クラスのランキング表を作成したい 4 2022/05/24 15:28
- Excel(エクセル) エクセル関数の変わった使い方 3 2022/05/13 17:12
- 予備校・塾・家庭教師 駿台。高三のクラス選択について。 駿台模試の数学偏差値が60あるので一応物理の難関クラス認定は貰って 1 2023/04/03 17:00
- HTML・CSS HTMLタグのあるCSVファイルを利用する方法 4 2023/03/19 14:41
- 英語 総称的意味の「the+過去分詞」が無冠詞複数形で置き換えることができない理由について 5 2022/08/04 10:14
- HTML・CSS WEBサイトの構築。表示データとWEBデザインを分離する考え方を専門用語・業界用語では何と言うか? 8 2022/09/27 09:16
- MySQL 【MySQL】本当に困っているので、助けてください。よろしくお願いします。 3 2023/06/03 14:24
- Visual Basic(VBA) Vba LongPtrについて教えてください 2 2022/08/19 11:14
このQ&Aを見た人はこんなQ&Aも見ています
-
性格の違いは生まれた順番で決まる?長男長女・中間子・末っ子・一人っ子の性格の傾向
同じ環境で生まれ育っても、生まれ順で性格は違うものなのだろうか。家庭教育研究家の田宮由美さんに教えてもらった。
-
c++,ある関数のクラスから別のクラスの関数を呼ぶ
C言語・C++・C#
-
画面を強制的に再描画させる方法
C言語・C++・C#
-
char*を初期化したいのですが
C言語・C++・C#
-
-
4
既定のコンストラクタがありません。というエラーについて
C言語・C++・C#
-
5
charからLPTSTRへの変換方法
C言語・C++・C#
-
6
クラスのアドレスを引数として渡したい
C言語・C++・C#
-
7
絶対パスの取得について
C言語・C++・C#
-
8
C++にてtemplateで受け取った任意の型の変数が何型であるかを判定したい
C言語・C++・C#
-
9
(マルチスレッド)_beginthreadexに複数の引数を渡す
C言語・C++・C#
-
10
CStringのFindで文字列検索を行いたいのですが
C言語・C++・C#
-
11
他の.CPPファイルに定義した関数を呼び出す方法について
C言語・C++・C#
-
12
unsigned long long 型のフォーマット指定子
C言語・C++・C#
-
13
「fatal error C1189」を回避するには?
C言語・C++・C#
-
14
静的でないメンバ関数の呼び出しが正しくありません
C言語・C++・C#
-
15
C++ 構造体の一括初期化 {0}
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
重複エラーを解決するには
-
グローバルIPとプライベートIP...
-
同一パッケージにあるクラスが...
-
河合塾のクラス分けについて
-
同じクラスにならない確率を教...
-
クラス見てから 女の子5人 ネタ...
-
コンボボックスのマウスホイー...
-
自作のクラスファイルがインポ...
-
クラスのプロパティに構造体を...
-
ドキュメントクラスの取得方法
-
配列の重複する値とその個数を...
-
複数のクラスで共通した関数を...
-
どこからも呼ばれていない無意...
-
dllと同じプロジェクトにする方法
-
1 つのヘッダファイルに複数の...
-
「天声人語」をインターネット...
-
java eclipse 型に解決できません
-
IPアドレスのクラスAを取得して...
-
プライベートIPアドレスについて
-
「囲うインスタンス」のエラー...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
3年間同じクラスになる確率
-
「天声人語」をインターネット...
-
配列の重複する値とその個数を...
-
自分事ですが、私のLINEのスク...
-
java eclipse 型に解決できません
-
同じクラスにならない確率を教...
-
どこからも呼ばれていない無意...
-
グローバルIPとプライベートIP...
-
担任にプレゼント
-
数学の計算問題。 3年間同じク...
-
クラスのプロパティに構造体を...
-
河合塾のクラス分けについて
-
IPアドレスのクラスAを取得して...
-
共通で使う関数を集めたクラス...
-
自作のクラスファイルがインポ...
-
1 つのヘッダファイルに複数の...
-
ヒートテックやファイバーヒー...
-
dllと同じプロジェクトにする方法
-
main()を持つクラスが2つ以上...
-
同一パッケージにあるクラスが...
おすすめ情報