アプリ版:「スタンプのみでお礼する」機能のリリースについて

C++なのですが、複数のクラスで共通して使いたい関数がある場合、親クラスに共通したい
メンバ関数を作り、その子として複数のクラスを作るのが良いのでしょうか?

それ以外の方法だとクラスの外でstatic宣言した関数であればクラス内で使えるようでした。
(static宣言しないとコンパイルエラーとなりました)

しかし以下のサイトにあるように「共通関数継承のデメリット」があるようで推奨していないようです。

ttp://d.hatena.ne.jp/katzchang/20110216/p1
ttp://blog.jnito.com/entry/20110217/1297896355

なお、自分には上記サイトの内容は難しくて理解できませんでした。
つまり、「数のクラスで共通して使いたい関数がある」場合、上記サイトはどうすればいいと言っているのでしょうか?

よろしくお願い致します。

A 回答 (11件中1~10件)

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);

}

などとすればいいです。
    • good
    • 0

もしかして



class A {
#include "inline.inl"
};

のような事をしてるって事なのでしょうか。
    • good
    • 0

一部訂正です。



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

No.10 でも書きましたが、おそらくそれらの関数を、クラスの外に出すだけで話は終わるでしょう。
    • good
    • 1

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



#3 への「お礼」のところについては, その ClassA::func を
・どのように呼び出しているのか
・どのように宣言しているのか
がわかればなんとかなるかもしれん.
    • good
    • 0

質問とは直接関係ありませんが


staticな関数であることと、その関数がスレッドセーフであるかどうかは無関係なので勘違いしないでくださいね。
    • good
    • 0

static をつけた関数は、「静的」という名称ではありますが、いわゆる「静的変数」とは別の概念です。



・クラスの外の static 関数
グローバルな static な関数は、ファイルスコープを持たせるためのものです。
通常、グローバルな関数は、暗黙の内に、外部スコープを持ち、(いっしょにリンクした)他のファイルにあるソースからも呼び出すことができます。
しかし、グローバルな static 関数は、同じファイルからしかアクセスできません。
#include で読み込む部分に、この「グローバルなstatic関数の実体」があると、複数読み込まれ、それは別々のものと扱われます。

グローバルな static 変数も、同様に、ファイルスコープを持たせるために指定するものです。

・クラスの中の static 関数
クラスの中にある static な関数は、「静的メンバ関数」と呼ばれます。
通常クラスの中にある関数は、生成されたインスタンスに附属するものです(ちょっと違う)
一方、クラスの中にある static なメンバ関数は、クラス全体をとりまとめる(少なくとも、個々のインスタンスに縛られない)情報にアクセスするためのものです。

 これは、(pubulic メンバなら)グローバルスコープを持ちます。
 従って、include されるファイルに関数の実体があると、「一つしかないはずのもの」が複数存在することになり、(コンパイルではなく)リンクで失敗することがあります。

個々のインスタンスに縛られないという性質から、static 関数だけからなるクラスを作って、ツールボックスのように使うこともできます。
しかし、この用途であれば、クラスではなく、namespace によるグループ分けをおすすめします。

クラスの中にある static メンバ変数も同様で、クラス全体の情報(インスタンスの数とか)を持ちます。

・関数の中にある static な変数
これが、「自動変数」に対する「静的変数」です。
    • good
    • 0

>それ以外の方法だとクラスの外で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つのプロジェクトを、複数人で開発し始めた時」にでも思い出せば良いです。
    • good
    • 0
この回答へのお礼

ありがとうございます。

>は、まったく異なる話。

そうですね…。読み返して改めて書き方がまずかったと思いました。

>「クラスの外でstatic宣言した関数」は、言わば「静的に確保した変数」みたいなモノで、スレッドセーブではないので、論外。お話にならない。

この質問を書いた後に一緒に仕事をしているプログラマさんに聞いたところ、私が記述しているコードは
全て「あるクラスの中」なのだそうです。

inline.inlとmain.cppに分かれていて、inline.inlに関数やクラスを宣言し、main.cppに実体を書いて、実装もしています。
このinline.inlとmain.cppが「あるクラスの中」だと言っていました。

※No.1~4さんの回答に「インクルードファイル」と書きましたが「inline.inl」というファイルでした。実際のファイル名は「inline」ではなくプロジェクト名に関する名前ですが拡張子はinlです。
間違ってすみませんでした。

>なので、こういう場合は「共通して使いたい関数だけが入ったクラス」を別に作って、Bが仕様変更を要求したら、クラスを継承した新クラスを作って、新クラスの方だけに仕様変更を盛り込む。

そういうことなのですね。よくわかりました。

>「全部一人でコーディングしている」なら、こんな事は気にしないで、好きに書いていれば良いよ。

かなり大規模なプロジェクトで担当しているのですが、自分が触っている部分に関しては私しかコーディングしないです。他のプログラマさんが見ることもほとんどないです。

お礼日時:2013/05/14 22:56

この場合、「複数のクラス」がどういうものなのかが問題です。



単に、(本質的に関係ない)いろいろなクラスで使い回したい便利な関数を集めるのであれば、既に回答があるように、通常の関数として定義すれば良いでしょう。
それらの「いろいろな関数」自体がある程度の共通性を持つなら、namespace という機能でグループ分けすることもできます。

逆に、「複数のクラス」というのが、「実は(もともと継承できるほど)共通性のあるもの」であれば、「元々共通的なクラス」に使うための(逆に言えば、他のクラス群では使わないだろうと思われる)関数(やデータメンバ)を含んだ、抽象クラスを作って、それを継承するというのは、間違いではありません。

※ただ単に、「便利そうな関数をまとめておきたい」という理由なら、クラスを使うべきではありません(が、namespace が見かけ上、ほぼ同じ用途に使えるでしょう)

親クラスで関数を定義して、それを、継承するというのは良い方法なのですが、「継承すべき」という状態でないと、途中で設計が破綻します。
設計が破綻した後でも、「継承」で乗り切ろうとすると、(それはつまり、本来やるべき事ではないことをやっているので)様々なデメリットが出てくるわけです。
    • good
    • 0
この回答へのお礼

ありがとうございます。

目的と使い方によってどう実装するかを変えるのですね…。
いちおう共有で使う関数はライブラリ化してあるインクルードファイルがあるのですが、
私が自作した関数はそこに入れることができず、自分のmain.cpp内でしか使わないので
どのように実装するのが良いのか、基準がぜんぜんわかりませんでした。

プログラマさんに聞いたところ、「継承でやるのではなくstaticを付けて宣言してください」とのことでした。

お礼日時:2013/05/14 22:48

必要そうな回答は既についているのでいいとして……。



>(static宣言しないとコンパイルエラーとなりました)

エラーメッセージをそのまま掲示した方がよいでしょう。
変な意訳とかは不要です。
    • good
    • 0
この回答へのお礼

ありがとうございます。

No.1さんの回答に付け加えて、エラーメッセージは以下のような感じでした。

main.cpp:error C2352 'ClassA::func':静的でないメンバー関数の呼び出しが正しくありません。
inline.inl:'ClassA::func'の宣言を確認してください。

お礼日時:2013/05/14 22:44

> 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を書いてくださいね。
    • good
    • 0
この回答へのお礼

ありがとうございます。

>クラスなどは使わず普通の関数として実装し、各クラスからはそれを単なる関数として呼ぶと良いでしょう。あるいは、その手の関数を集めたユーティリティクラスを作り、それを呼ぶかでしょう。

大規模プロジェクトの一部を担っているのですが、関数を集めたライブラリはあります。
しかし私が自分で使うだけの関数はそこに追加できないことになっています。

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を書いてくださいね。

すみませんでした。勝手に他サイトをリンクするとそのサイト運営者に迷惑かなと思ったので…。
以後気をつけます。

お礼日時:2013/05/14 22:43

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています