
継承したクラスを、継承元のクラス型の引数に渡すとどうなるのでしょうか?
以下のようなケースで、
#include "stdio.h"
using namespace std;
// baseクラス
class base {
private:
int m_nII;
int m_nJJ;
int m_nKK;
public:
base(int i,int j,int k){ m_nII=i; m_nJJ=j; m_nKK=k; }
int GetSum(){ return (m_nII+m_nJJ+m_nKK); }
};
// base 継承クラス
class hoge : public base {
public:
hoge() : base(1,2,3){}
};
void func(base* obj){ // baseクラスを引数に取る関数
printf("sum is %d\n", obj->GetSum());
}
// main
int main(){
hoge objHoge;
func((base*)&objHoge); // <-キャストして渡す
return 0;
}
として、一応、gccでコンパイルは通り、実行結果も期待通りだったのですが、
このやり方で問題は無いのでしょうか?
(たとえば継承先のクラスが独自のメンバを持っていたりなどした場合、期待した結果にならないとか・・)
よろしくお願いします。
No.2ベストアンサー
- 回答日時:
言語仕様通りで問題ありません。
実行時の挙動の話をすると、
1.プログラムは関数と変数に分けられてメモリ上に配置される
プログラムがメモリにロードされて命令が実行される段階では、プログラムはテキスト領域、静的領域、ヒープ領域、スタック領域に分けられて実行されます。
テキスト領域には、関数が機械語に翻訳された内容が格納されますので、このことからメンバ関数を増やしても問題になりません。
2.メンバ変数は基底(継承元)クラスのメンバの後に継承クラスのメンバが継ぎ足しされる。
hoge のインスタンス(obj)のメモリ上の配置
1000から1019のアドレスにobjは格納される。
1000から1011のアドレスにobjのbaseクラスのメンバが格納される。
1012から1019のアドレスにobjのhogeクラスのメンバが格納される。
1000: base.m_nII; // base クラスのメンバ変数(obj)
1004: base.m_nJJ; // 〃
1008: base.m_nKK; // 〃
1012: hoge.m_anpan; // hoge クラスで追加したメンバ変数
1016: hoge.m_pizza; // 〃
3.メンバ関数は、構造体へのポインタを受け取る関数
「func」関数の引数で「base *obj」を指定し「obj->GetSum()」と呼び出すことは
「static int base::GetSum(base *obj)」の呼び出しと同じである。
つまり、構造体へのポインタを引数とする関数に等しい。
// 以上のことをC言語に直すとこんな風になります。
struct base { int m_nII, m_nJJ, m_nKK; };
struct hoge { struct base base; int m_anpan, m_pizza; };
void base_init(struct base *obj, int i, int j int k)
{ obj->m_nII = i; obj->m_nJJ = j; obj->m_nKK = k; }
int base_GetSum(struct base *obj)
{ return obj->m_nII + obj->m_nJJ + obj->m_nKK; }
void hoge_init(struct hoge *obj)
{ base_init((struct base *)obj, 1, 2, 3); obj->m_anpan = 120; obj->m_pizza = 3000; }
int hoge_GetPizza(struct hoge *obj)
{ return obj->m_pizza; }
int main() {
struct hoge obj; hoge_init(&obj);
printf("sum is %d\n", base_GetSum((struct base *)&obj));
obj.m_anpan = 1200;
printf("Anapn is \\%d\n", obj.m_anpan);
printf("Pizza is \\%d\n", hoge_GetPizza(&obj));
// アドレス表示
printf("obj.base.m_II : %x\n" &obj.base.m_II);
printf("obj.base.m_JJ : %x\n" &obj.base.m_JJ);
printf("obj.base.m_KK : %x\n" &obj.base.m_KK);
printf("obj.m_anpan : %x\n" &obj.m_anpan);
printf("obj.m_pizza : %x\n" &obj.m_pizza);
return 0;
}
ポイントは、クラスという概念は関数と構造体を一体的に扱う仕組みであり言語仕様上にのみ存在し、実行時にメンバ関数は単純な引数渡しと関数呼び出しになるということです。
関連として、関数のオーバーライド、ポリモルフィズムなどがありますが、それの実体は構造体のレコードに関数ポインタ配列へのポインタを持たせているだけです。
つまり理解するには、C言語の関数ポインタ、関数ポインタの配列について理解することが、遠回りですが近道になります。
# 理解しなくても使うことはできますが(ーー;)
あと、コードっぽいのは適当に書いただけなので間違いがあると思います。
参考URL:http://brain.cc.kogakuin.ac.jp/~kanamaru/lecture …
No.1
- 回答日時:
全く問題ないですよ。
よく使われる手法です。C++には欠かせないテクニックで、ポリモーフィズムを実現する方法の一つですね。継承先のクラスが同名の独自のメンバを持っている(今回はhogeクラスがint GetSum()を持っていた)場合に、どっちが呼ばれるかは、このソースではbaseの方になります。これを、hogeの方を呼ばせたければbaseのint GetSum()にvirtualというキーワードをつけます。
この辺の詳しいお話は「オーバーライド」や「仮想関数(virtual)」などをキーワードに検索してみてください。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# プログラミングのペーパーテスト 実行結果を表示せよ #include <stdio.h> int h 1 2022/07/09 15:27
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- Ruby パイソンプログラミング 2 2022/12/03 18:44
- C言語・C++・C# プログラミングペーパーテスト 次の問題の実行結果を答えろ #include int x[ ] = { 1 2022/06/16 21:49
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミングの授業のペーパーテスト 実行結果を答えろ #include int x[ ] = {1 3 2022/06/16 20:08
- C言語・C++・C# 至急教えてください! プログラミングの問題です! お願いします! 出力2と全く同じ出力をするように、 2 2022/06/22 23:10
- C言語・C++・C# C言語階乗の総和を求める 2 2023/03/04 23:31
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・「それ、メッセージ花火でわざわざ伝えること?」
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・【お題】甲子園での思い出の残し方
- ・【お題】動物のキャッチフレーズ
- ・人生で一番思い出に残ってる靴
- ・これ何て呼びますか Part2
- ・スタッフと宿泊客が全員斜め上を行くホテルのレビュー
- ・あなたが好きな本屋さんを教えてください
- ・かっこよく答えてください!!
- ・一回も披露したことのない豆知識
- ・ショボ短歌会
- ・いちばん失敗した人決定戦
- ・性格悪い人が優勝
- ・最速怪談選手権
- ・限定しりとり
- ・性格いい人が優勝
- ・これ何て呼びますか
- ・チョコミントアイス
- ・単二電池
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・ゴリラ向け動画サイト「ウホウホ動画」にありがちなこと
- ・泣きながら食べたご飯の思い出
- ・一番好きなみそ汁の具材は?
- ・人生で一番お金がなかったとき
- ・カラオケの鉄板ソング
- ・自分用のお土産
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エディットコントロールでEnter...
-
C++ protectedにアクセス不可
-
既定のコンストラクタがない?
-
MFCのCListCtrlでスクロールを検出
-
VB.NETでC#のイベントをオーバ...
-
OnPaintとOnDraw関数の違いにつ...
-
FriendとPublicの違い。。。
-
クラスのアドレスを引数として...
-
windowプログラム ピクチャー...
-
MFCアプリのコマンドラインでパ...
-
テンプレート指定クラスのコン...
-
【ASP.NET】 独自で作成したク...
-
MFCのドラッグ&ドロップについて
-
イベントにAddHandlerされてい...
-
C#で通常のbuttonコントロール...
-
[MFC] CWnd::MessageBoxの警告...
-
.cppファイルにはclassを書かな...
-
ボタンのオーナードローについて
-
IncludeではなくClassで宣言す...
-
(UWSC) 「#32770」の意味わかり...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
既定のコンストラクタがない?
-
FriendとPublicの違い。。。
-
(UWSC) 「#32770」の意味わかり...
-
ダイアログ表示時にチェックボ...
-
クラスのアドレスを引数として...
-
イベントにAddHandlerされてい...
-
エディットコントロールでEnter...
-
エディットコントロールのイベ...
-
【ASP.NET】 独自で作成したク...
-
個々の関数について継承してい...
-
C++ protectedにアクセス不可
-
MFCアプリのコマンドラインでパ...
-
DataGridViewのセルに斜線を引...
-
C#で通常のbuttonコントロール...
-
ソケットを使った「非同期」通...
-
MFCのドラッグ&ドロップについて
-
オーバーライド関数の呼び出し...
-
[MFC] CWnd::MessageBoxの警告...
-
ボタンのオーナードローについて
-
C++/CLIからC++の呼び出しで例外
おすすめ情報