仮想関数とは何ですか? – プログラミング – Home

仮想関数とは何ですか?
 
通知
すべてクリア

[解決済] 仮想関数とは何ですか?

固定ページ 1 / 2

たま
 たま
(@たま)
ゲスト
結合: 23年前
投稿: 50
Topic starter  

プログラムの質問ではないですが、教えてください。

最近、Visual C++ をはじめたのですが、どうも仮想関数というものを使う必要性がわか
りません。
どんなときに使うのか?やこのような場合は仮想関数でなければいけないなどがあれば
教えてください。

すみませんがお願いします。


引用未解決
トピックタグ
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

大抵のC++参考書に説明があります。お読みになりましたか?


返信引用
たま
 たま
(@たま)
ゲスト
結合: 23年前
投稿: 50
Topic starter  

参考書を読んでどんなものかはわかりましたが、いまいち使用目的がわからないんです
よね。
それで困っていたんです。


返信引用
晃
 晃
(@晃)
ゲスト
結合: 20年前
投稿: 9
 

> いまいち使用目的がわからないんですよね。
派生したクラスごとに動作を変えたいときです。
基底クラスのポインタなどからメンバ関数へアクセスするときに役立ちます。


返信引用
SunPac
 SunPac
(@SunPac)
ゲスト
結合: 21年前
投稿: 105
 

まあ、使わなくていいのなら無理して使うこともないですよ。

・・・といいたい所だけど、仮想関数ってすごく重要なのでそうもいってられないかな。
オブジェクト指向の入門書でも読めば「ああ、なるほど!」って思えるはず。

あとはEffectiveC++かなぁ。


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

# それだけで納得できる人なら最初から質問しないだろうとか思ったり...

いつも使っている例(何回か書いた)

//「画面に描画できるものクラス」
//描画できる性質を持っているが、具体的にどんなふうに描画するかは関知しない
class drawable { ...
virtual void draw()=0;
};
//直線クラス、長方形クラス、円クラス、その他
//「描画できる性質」は共通だが、具体的にどんな図を描くかはすべて違う
class line : public drawable { ...
virtual void draw() { ... }
};
class rectangle : public drawable { ... } // 詳細略
class circle : public drawable { ... } // 詳細略

// 「画面に描画できるもの」であるなら、何でも受け取れる関数
// 実際には line かもしれないし rectangle かもしれない
void drawit(drawable* obj) {
obj->draw();
}

drawit() は drawable クラスの draw() を字面上呼び出しています。
が、この draw() は virtual なので、この字面上の呼び出しは実際には
派生クラス (line/rectangle/circle) の draw() を呼び出します。

実行時までどのクラスの draw() を呼ぶべきか判らない、動的解決が必要な場合に
virtual を使います。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

私が良く使うパターンだと

class CShape { ...
public:
virtual void draw() { ... }
};

class Polyline : public CShape { ... };
class Polygon : public CShape { ... };
class Circle : public CShape { ... };

class XXX { ...
CShape* m_shapes[10];

void DrawShapes();
};
void XXX::DrawShapes()
{
  int i;
  for(i = 0; i < 10; i++)
  {
    if(m_shapes[i] != NULL)
    {
      m_shapes[i]->draw();
    }
  }
}

相当省略していますのでそのまま使えませんが、
要はm_shapesにはCShapeクラスから派生したさまざまなクラスが入りえますが、
その全ての描画を上記のコードで呼び出すことが出来ます。
これが、仮想関数を使わないと、それぞれのインスタンスが何者かで
呼び出すためのコードを変えなくてはならなくなります。
これによってコードが非常にすっきりすることがわかると思います。
また、CShapeから派生し、drawメソッドをオーバーライドしていれば、
新しいクラスを追加しても呼出側は影響を受けません。
drawの実装を強制したいのであれば、

class CShape { ...
public:
virtual void draw() = 0;
};

として純粋仮想関数にすれば、派生側の実装を縛ることも可能です。
こういう使い方をするには設計そのものをオブジェクト指向でやってないと
無理があるかもしれません。


返信引用
くたくた
 くたくた
(@くたくた)
ゲスト
結合: 23年前
投稿: 119
 

コールバック関数はご存知ですか?
Cの標準関数のbsearch()やqsort()に渡し、内部で使われる関数がそれです。

これの「メンバ関数版」が(純粋)仮想関数です。

細かい違いはあれど、動作自体はまさしくそれです。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 21年前
投稿: 600
 

> 細かい違いはあれど、動作自体はまさしくそれです。

ここではメカニズム(からくり)の話はしてないと思う。


返信引用
くたくた
 くたくた
(@くたくた)
ゲスト
結合: 23年前
投稿: 119
 

>ここではメカニズム(からくり)の話はしてないと思う。
ん? どういう事でしょう?ちょっとよく分かりませんでした(^^;

「どんなときに使うのか?」という質問だったので、
「コールバック関数のように使う」というお返事をしたのでした。


返信引用
くたくた
 くたくた
(@くたくた)
ゲスト
結合: 23年前
投稿: 119
 

>επιστημηさん
ああ、分かりました!
「私が言った「動作自体」というのが、仮想関数を動作させる為の内部的なからくり
を指している」という事を仰ってるのですね。

失礼乍、言葉足らずでした(^^;
「動作自体」はそれを指しているのでなく、「コールバック関数が内部で呼ばれる」
事を指しています。


返信引用
晃
 晃
(@晃)
ゲスト
結合: 20年前
投稿: 9
 

> それだけで納得できる人なら最初から質問しないだろうとか思ったり...
ぎゃ。そうですよね、大変失礼しました。。。
#サンプルも書いたんだけど長くなったので消しちゃったんです^^;
これだけでは無責任な感じなので追加します。
コードはもう出ているのですが僕なりにも書いてみました。

class text { //テキスト
public:
char* str;
virtual void write() { cout << str; }; //普通に書く
};
class comment : public text { //コメント
public:
virtual void write() { cout << ( << str << ); }; //括弧でくくって書く
};
class note : public text { //注釈
public:
virtual void write() { cout << note: << str; }; //頭にnote:を付けて書く
};
これで、例えば次のような関数にtextやcomment,note型などのポインタが
混ざった配列を渡しても、きちんとcomment型だったものは括弧でくくられ、
note型だったものはnote:がついて出力できるんです。
write_text(text* p /*textの配列*/, int n /*配列の要素数*/) {
for(int i=0;i<n;++i)
p->write();
};
こんな感じで派生したクラスたちを
配列などで一括管理するときに仮想関数は使えると思います。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 21年前
投稿: 600
 

>「どんなときに使うのか?」という質問だったので、
>「コールバック関数のように使う」というお返事をしたのでした。

うーん…むしろ「コールバック関数のように使うことができる」ではないかしら。

図形に属するならば円だろが三角だろが四角だろが、
それぞれに応じた'描画'を用意しておけば、
なんか知らんけどとにかく図形に対して'描画'と言えばよきに計らってくれる。

それが(仮想関数で実現された)'多態'のキモであり使いみちではないかと。


返信引用
くたくた
 くたくた
(@くたくた)
ゲスト
結合: 23年前
投稿: 119
 

>むしろ「コールバック関数のように使うことができる」ではないかしら。
あ、その方が正確かな?どうも有難う御座います。
「クラスインスタンスに対してのコールバック関数みたいな奴」って感じで。

Cで多態させるとvoid*やら何やらで危なっかしいんですが、C++ではきちんと自動生成し
てくれますよね。初めて実務で使った時は、随分感動しましたよ~。


返信引用
たま
 たま
(@たま)
ゲスト
結合: 23年前
投稿: 50
Topic starter  

正直、これほどのスレがあるとは思っておりませんでした。
ほんとに皆様、どうもありがとうございます。

参考書を見たときに、virtual をつければ仮想関数です・・・みたいな柿か確かしてい
なかったので。
ついでといっては何ですが、VC++ .NET またはオブジェクト指向を独学で学ぶのによい
参考書を知っていたら教えてください。
現在の私のレベルは入門者ととっていただいてかまいませんので、その辺も踏まえてお
願いいたします。

あつかましくてすみません。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました