質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

4696閲覧

ポリモーフィズムの仕組み

reotantan

総合スコア295

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

2グッド

0クリップ

投稿2015/12/20 15:29

編集2015/12/21 23:27

ポリモーフィズムの実装で、原型クラスのポインタを使って、なぜ派生クラスを指し示すようになったのでしょうか?
class Girl;public Humanというのは物理的にどのように設定されているのでしょうか?
humanクラスから派生されたから、human classのポインターで派生クラスを示せるというのは概念的、機能的には理解できますが、それがどのようにプログラムされたのか気になりました。
派生というものが、どのように実装されたのかに触れて説明していただけると嬉しいです。
皆さま、よろしくお願いします。

お二方、仮想関数についてはよく理解できました、ありがとうございました!
しかしptr=&aliceについて疑問があります。
ptrはhumanクラスのポインターであって、ガールやボーイクラスのポインタではないですよね、ポインタはどのように、指すクラスが適切なのかを判断しているのでしょうか?
全く関係ない魚クラスを作って、humanクラスのポインタでは指すことはできませんよね。
度々申し訳ありません、よろしくお願いします。

コード class Human{ // 基底クラス public: virtual void speak(){ printf("I am human.\n"); } // 仮想関数 }; class Girl : public Human{ public: void speak(){ printf("I am girl.\n"); } }; class Boy : public Human{ public: void speak(){ printf("I am boy.\n"); } }; int main(void) { Human *ptr; Girl alice; Boy bob; ptr=&alice; ptr->speak(); ptr=&bob; ptr->speak(); return(0); }
yoshi777, Chironian👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

C++でvirtualを使うと、暗黙的なインスタンス変数としてジャンプテーブルが作られ、コンストラクタでそこにvirtualな関数のポインタが格納されます。

C++

1class Human{ // 基底クラス 2public: 3 virtual void speak(){ printf("I am human.\n"); } // 仮想関数 4protected: 5 void** jumpTable; // この中にspeak()関数のポインタが入ります。 6};

GirlやBoyなどの派生クラスのコンストラクタは、このジャンプテーブルの内容を自分用に上書きします。

virtualな関数を呼び出そうとすると、このジャンプテーブル内の関数ポインタを使って動的に関数を呼び出すコードがコンパイラによって生成されます。


ポインタはどのように、指すクラスが適切なのかを判断しているのでしょうか?

これは、「コンパイラはどのように、指すクラスが適切なのかを判断しているのでしょうか?」ということですよね?
単純に、クラスの継承関係を見て判断しています。

humanクラスから派生されたから、human classのポインターで派生クラスを示せるというのは概念的、機能的には理解できますが

継承関係があれば問題ないことは、理解しているということでいいんですよね?

投稿2015/12/20 16:39

編集2015/12/22 16:56
Stripe

総合スコア2183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reotantan

2015/12/24 01:29

解説ありがとうございました。とても理解が進みました
guest

0

すいません、取り急ぎリンクだけ。
ここが分かりやすかったです。


【追記】
virtualをつけるとその関数へのポインタAが、クラスの隠しメンバ変数としてこっそり追加されます。
具体的には下記のようになります。

HumanクラスのポインタAには、void speak(){ printf("I am human.\n"); }へのポインタ Girl クラスのポインタAには、void speak(){ printf("I am girl.\n"); } へのポインタ Boy クラスのポインタAには、void speak(){ printf("I am Boy.\n"); } へのポインタ

そして、ptr=&alice;の時、ptrはGirlクラスのインスタンスを指しているため、
そのポインタAにはvoid speak(){ printf("I am girl.\n"); }へのポインタが入ってます。
従って、ptr->speak();を呼び出すと、void speak(){ printf("I am girl.\n"); }が呼ばれます。
bobの場合も同様なのです。

なお、仮想関数は複数存在できるので、隠し関数ポインタは配列として実装され、vtableと呼ばれています。

投稿2015/12/20 16:03

編集2015/12/21 00:45
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

reotantan

2015/12/24 01:30

解説ありがとうございました、vtableしっかりと勉強します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問