趣味+メモ用のブログです。
GNU/Linux関連、OSS関連情報、調査事項になるでしょうが、何を書くか分かりません。
× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
C++の継承で実験
結果からいうと、 ・ベースクラスのポインタで読んだメソッドは、 ベースクラスのメソッドが呼ばれる。 →型依存の呼び出し ・間接呼び出しをした場合、private/protectedに関係なく virtualをつけたメソッドは、オブジェクト実態が呼び出される →オブジェクト依存の呼び出し ・継承時の、virtualは効果がない ・virtualをつけたメソッドは、オブジェクト依存の呼び出し ・virtualをつけなかったメソッドは、クラス依存の呼び出し となる。 ■検証用コード(test.cpp) 1 #include <stdio.h> 2 3 // ベースクラス 4 class Base{ 5 public: 6 void direct(){ // 直接呼び出し用 7 printf( "Base::direct() \n" ); 8 } 9 virtual void directVirtual(){ 10 printf( "Base::directVirtual() \n" ); 11 } 12 void indirect(){ // 間接呼び出し用 13 this->doPrivate(); 14 this->doPrivateVirtual(); 15 this->doProtected(); 16 this->doProtectedVirtual(); 17 } 18 private: 19 void doPrivate() { printf( "Base::doPrivate() \n" ); } 20 virtual void doPrivateVirtual(){ printf( "Base::doPrivateVirtual() \n" ); } 21 protected: 22 void doProtected() { printf( "Base::doProtected() \n" ); } 23 virtual void doProtectedVirtual(){ printf( "Base::doProtectedVirtual() \n" ); } 24 }; 25 26 // サブクラス1(普通に継承) 27 class Sub1: public Base{ 28 public: 29 void direct() { printf( "Sub1::direct \n" ); } 30 virtual void directVirtual(){ printf( "Sub1::directVirtual() \n" ); } 31 private: 32 void doPrivate() { printf( "Sub1::doPrivate() \n" ); } 33 virtual void doPrivateVirtual(){ printf( "Sub1::doPrivateVirtual() \n" ); } 34 protected: 35 void doProtected() { printf( "Sub1::doProtected() \n" ); } 36 virtual void doProtectedVirtual(){ printf( "Sub1::doProtectedVirtual() \n" ); } 37 }; 38 39 // サブクラス2(virtualで継承) 40 class Sub2: public virtual Base{ 41 public: 42 void direct() { printf( "Sub2::direct \n" ); } 43 virtual void directVirtual(){ printf( "Sub2::directVirtual() \n" ); } 44 private: 45 void doPrivate() { printf( "Sub2::doPrivate() \n" ); } 46 virtual void doPrivateVirtual(){ printf( "Sub2::doPrivateVirtual() \n" ); } 47 protected: 48 void doProtected() { printf( "Sub2::doProtected() \n" ); } 49 virtual void doProtectedVirtual(){ printf( "Sub2::doProtectedVirtual() \n" ); } 50 }; 51 52 53 int main() 54 { 55 Base* ptr = NULL; 56 Base base; 57 Sub1 sub1; 58 Sub2 sub2; 59 60 printf( "== Base ==\n" ); 61 ptr = &base; 62 ptr->direct(); 63 ptr->directVirtual(); 64 ptr->indirect(); 65 66 printf( "== Sub1 ==\n" ); 67 ptr = &sub1; 68 ptr->direct(); 69 ptr->directVirtual(); 70 ptr->indirect(); 71 72 printf( "== Sub2 ==\n" ); 73 ptr = &sub2; 74 ptr->direct(); 75 ptr->directVirtual(); 76 ptr->indirect(); 77 78 return 0; 79 } ■結果 $ g++ --version g++ (Debian 4.7.2-5) 4.7.2 Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ g++ test.cpp $ ./a.out == Base == Base::direct() Base::directVirtual() Base::doPrivate() Base::doPrivateVirtual() Base::doProtected() Base::doProtectedVirtual() == Sub1 == Base::direct() Sub1::directVirtual() Base::doPrivate() Sub1::doPrivateVirtual() Base::doProtected() Sub1::doProtectedVirtual() == Sub2 == Base::direct() Sub2::directVirtual() Base::doPrivate() Sub2::doPrivateVirtual() Base::doProtected() Sub2::doProtectedVirtual() Javaだと、Sub1 / Sub2はすべて子クラス側の メソッドが呼び出されるため、注意が必要!! ちなみに、独習C++での結果とはちがっている。 (すみません。あっています) Javaと同様の動きにするには、メソッドにvirtualをつける必要がある。 ただし、virtualをつけることにより、命令数は増え、負荷は高くなる。 ■ virtual有無によるアセンブルの確認 $ g++ -g test.cpp $ objdump -C -S -l ./a.out ・・・ /home/sakaihdt/test/c++/subclass/test.cpp:62 ptr->direct(); 80486c5: 8b 44 24 1c mov 0x1c(%esp),%eax 80486c9: 89 04 24 mov %eax,(%esp) 80486cc: e8 a9 00 00 00 call 804877a <_ZN4Base6directEv> /home/sakaihdt/test/c++/subclass/test.cpp:63 ptr->directVirtual(); 80486d1: 8b 44 24 1c mov 0x1c(%esp),%eax 80486d5: 8b 00 mov (%eax),%eax 80486d7: 8b 00 mov (%eax),%eax 80486d9: 8b 54 24 1c mov 0x1c(%esp),%edx 80486dd: 89 14 24 mov %edx,(%esp) 80486e0: ff d0 call *%eax ・・・ PR |
カレンダー
カテゴリー
フリーエリア
最新コメント
最新記事
(05/02)
(01/25)
(01/15)
(12/04)
(12/01)
最新トラックバック
ブログ内検索
最古記事
(02/21)
(07/12)
(07/12)
(07/18)
(07/20) |