🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

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

Q&A

解決済

1回答

1226閲覧

仮想関数を用いて派生クラスのオブジェクトを返すときについて

Takayou

総合スコア15

C++

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

1グッド

0クリップ

投稿2019/09/11 09:34

「独習C++」のサンプルコードでわからないところがあります.
以下のプログラムでは,画面上に図形の形状を描くクラス階層を定義しています.
階層の上部には抽象クラスShapeがあります.
具体的なサブクラスとして, 以下の4つの派生クラスを定義しています.

  • 長方形を描くRectangleクラス
  • 三角形を描くTriangleクラス
  • 直線を描くLineクラス
  • 何も描かないNullShapeクラス

実際のプログラムは以下です.

C++

1//図形を表示するプログラム 2#include<iostream> 3#include<cstdlib> 4#include<typeinfo> 5using namespace std; 6 7class Shape{ 8public : 9 virtual void func() = 0; 10}; 11 12class Rectangle : public Shape{ 13public : 14 void func(){ 15 cout << "Rectangle" << endl; 16 cout << "*******" << endl << "* *" << endl << "*******" << endl << endl;; 17 } 18}; 19 20class Triangle : public Shape{ 21public : 22 void func(){ 23 cout << "Triangle" << endl; 24 cout << "*" << endl << "* *" << endl << "*****" << endl << endl; 25 } 26}; 27 28class Line : public Shape{ 29 void func(){ 30 cout << "Line" << endl; 31 cout << "********" << endl<< endl; 32 } 33}; 34 35class NullShape : public Shape{ 36 void func(){ 37 cout << "Nullshape" << endl << endl; 38 } 39}; 40 41 42 43Shape *generator() 44{ 45 switch(rand()%4){ 46 case 0: 47 return new Line; 48 case 1: 49 return new Rectangle; 50 case 2: 51 return new Triangle; 52 case 3: 53 return new NullShape; 54 } 55 return NULL; 56} 57 58int main() 59{ 60 int i; 61 Shape *p; 62 63 for(i=0; i<10; i++){ 64 p = generator(); 65 66 cout << typeid(*p).name() << endl; 67 68 //Nullでないときのみ,オブジェクトを描画する 69 if(typeid(*p) != typeid(NULL)){ 70 p->func(); 71 } 72 } 73 74 return 0; 75} 76 77

ここで,以下の部分について質問があります

C++

1Shape *generator() 2{ 3 switch(rand()%4){ 4 case 0: 5 return new Line; 6 case 1: 7 return new Rectangle; 8 case 2: 9 return new Triangle; 10 case 3: 11 return new NullShape; 12 } 13 return NULL; 14}

この*generator()関数の返り値は
return new classname
となっています.

なぜ, ここでnewを用いる必要があるのでしょうか?
仮想関数に関して理解が不十分で,ここの部分で何が起きているのかわかりません.

説明が長くてすみません,どなたかお力を貸してください…!

Bull👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

返り値はShapeのポインタですから、return Line();と書くことは出来ません

Line line; return &line; なら構文的には間違っていませんが、
lineはローカル変数ですから、関数を抜けた時点で実体が消滅します
これは、解放済みメモリのポインタを返すので重大なバグになります

ですから、関数を抜けても消滅しない実体を返す必要があるのでreturn new Line();となります

#実体、の部分って理解できていますか?

投稿2019/09/11 09:39

izmktr

総合スコア2856

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

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

Takayou

2019/09/11 10:50

回答していただきありがとうございます. - return Line; と書くと, main()で p = Lineとなり型が違うためエラー - return &lineと書くと, main()で, p = &lineとなり,構文的には合っているが, lineはスコープから外れてしまうためバグが生じる ということでよろしいのでしょうか...? 2つ目に関してなのですが. 「関数を抜けた時点でオブジェクトが破棄されると同時に,戻り値を格納する一時オブジェクトが自動的に作成される」と思っていたのですが違うのでしょうか? また,new lineとすると実体が消滅しない,というのがなぜなのかわからないです... 実体は関数内のオブジェクトと同じオブジェクト(アドレスが同じ)という理解でいいのでしょうか...?
izmktr

2019/09/11 11:26

もし、返り値がLineなら、返り値を格納する一時オブジェクトが生成されますが、 返り値が「Line *」のため、作成されるのは「Lineのポインタ」であり「Lineの実体」ではありません deleteを実行するまで実体を絶対に消すな、というルールを敷くのがnewです ですから、deleteがないと永遠にメモリを専有するメモリリークとなります
Takayou

2019/09/11 11:44

「newでメモリ確保しているわけではないポインタ」は関数を抜けるときに勝手にメモリが消えてしまい,実体が消滅する,という理解でよろしいでしょうか?
izmktr

2019/09/11 13:41

「newでメモリ確保しているわけではないポインタ」ってのは、要は「ポインタ」ですよね ポインタは実体ではありません 実体、ポインタなどの単語の意味を本でもう一度確認して書くようにしてください 関数が~とか考えるのではなく{}で囲まれた領域をスコープと呼び、 そのスコープを抜けると変数名は参照できなくなるし、同時にその変数で使われていたメモリも解放されます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問