47245


オブジェクト指向で「静的な型と動的な型」という用語が出てきたのですが、説明を読んでもわかりません。参考書には以下のように書かれているのですが、"式"というところで引っ掛かり結果よくわからないまま参考書を読み進めていましたが理解している前提での説明が続いてその先の理解できないので別の説明をしてもらいたく質問しました。

* * *

**静的な型**

> 「静的な型
> 式の型、その式がもたらす結果の型として実行時の意味を考慮ぜずにプログラムを解析することで得られる。式の静的な型は、その式が位置するプログラムの形だけから決まり、プログラムの実行中に変わることがない。」

**動的な型**

> 「動的な型。左辺値式の表す左辺値が指す最派生オブジェクト型。(例)
> その静的な型がクラスBへのポインタであるポインタｐがクラスBから派生したクラスDのオブジェクトを指していたとすると、式*pの動的な型はDとなる、参照も同様に扱う。右辺値式の動的な型は、それの静的な型とする。」

* * *
[code]

            void put_member(const Member* m) {
                cout << (m->get_weight() >= 65 ? "〇" : "　");
                m->print();//ここです。
            }
    
            int main() {
    
                Member m("mmm", 15, 75.2);
                VipMember v("aaa", 17, 89.2, "会費全額免除");
                SeniorMember s("sss",43,63.7,3);
    
                put_member(&m);
                put_member(&v);
                put_member(&s);
    
                _getch();
                return 0;
            }
    
[/code]


CC BY-SA 4.0
2018-08-04T11:23:03.550
47243
2018-08-07T04:05:19.457
2018-08-04T15:25:26.257
76
question
c++
静的な型と動的な型の意味が知りたい。


難しく考えすぎです。  
とりあえず「式」という単語を使わない説明をしてみます。

提示サンプルが断片的過ぎて、そのサンプルではコメントできないです。  
[c++ 仮想関数の利点について](https://ja.stackoverflow.com/questions/47194/)  
のコードをサンプルとして使います。

[code]

    b* p=&d;
    
[/code]

において、静的な型とは  
- `p` はソースコード上 `b*` と書かれていますから `b*` が静的な型  
- `&d` はソースコード上 `d1*` と読めるので `d1*` が静的な型
[code]

    p->f1();
    
[/code]

`p->` は `(*p).` の省略形だと思い出してください。ここで

  * `*p` の静的な型とはソースコードを素直に読んだ `b` 型のこと
  * `*p` の動的な型とはこの例では `d1` 型のことです。

先の例ではソースコードが簡単すぎて「読むだけ」で動的な型が判断できてしまいますが、もう少し実用的なサンプルコードを示すと

[code]

    void func(b* p) { p->f1(); }
    int main() {
        b x; func(&x);
        d1 y; func(&y);        
    }
    
[/code]

のようになります。この場合 `func` 中の `*p` の

  * 静的な型は `b`
  * 動的な型は `b` か `d1` か、実行するまでわからない（１回目は `b` ２回目は `d1` ）

ってことです。


CC BY-SA 4.0
2018-08-04T12:17:53.587
47245
2018-08-07T04:05:19.457
2018-08-07T04:05:19.457
29081
8589
47243
answer


一般に静的な型付けとはプログラマがソースコード内に型を宣言して記述するものです。  
（それはautoやvarなどの型推論も含む、型推論は初期化値である右辺値から型を推論し左辺値の型とせよというプログラマからの宣言であると解釈できる。）  
静的な型付けがされた変数にはその型に適したものしか格納できないようになります。  
int型変数に文字列を代入することはできません。  
型を宣言するということは、変数に対してそうした制約を課する行為であるといえます。  
ソースコードをコンパイラに渡した時点でその変数は格納できるものが決まっているわけです。  
(これを静的な型とここでは呼ぶことにします。プログラマが指定する型です。)

一方で世の中には型を宣言しなくても動作する言語がありますよね（javascriptとか）  
これはプログラマが型を宣言しなくても数値と文字列が区別されます。  
そのギミックについて理解するには、そうした言語では変数(左辺値)が型を持つのではなく値(右辺値)自体が型を持っていると考えればいいのです。  
たとえばjavascriptにおいては、var x =
"abc";と記述すると、xには{type:"String",value:"abc"}というような型を持った値が格納されるとイメージすればすんなり理解できます。  
そこにさらにvar x =
1;と記述するとxには{type:"Number",value:1}といった値が格納されると考えると、xに型宣言をする意味自体がないわけです。型宣言しなくてもコンピュータは実行するに十分な情報を獲得できます。  
(これを動的な型と呼ぶことにします。値自身が保持する型です。)

さてC++におけるオブジェクト指向についてですが、オブジェクト指向には継承やポリモーフィズムという概念があることはご存知だと思います。  
継承の難しさは宣言された型と、値自身が保持する型が必ずしも一致しないということになります。親クラスのポインタで派生クラスのオブジェクトを指してもエラーにはなりません。  
動的な型が確定するのはいつか？それはオブジェクトがコンストラクタによって生成された時点でしょう。事実上継承がある状態においては型宣言はあまり意味をもちません。動的な型が実行時における挙動を決めます。  
(もちろん明らかに誤った型宣言をコンパイラ時にエラーとして返すぐらいの効力はありますが)  
継承というのは純粋な静的の型宣言を要する言語(C)と動的に型を解釈する言語(javascript)の中間にあるような機能だと捉えるといいです。C++はCを踏襲しているので、文法的に左辺値の型宣言を必要としますが、オブジェクト指向において実際の挙動を決めるのは右辺値に格納されている型なのです。


CC BY-SA 4.0
2018-08-04T16:40:07.827
47247
2018-08-04T17:20:16.427
2018-08-04T17:20:16.427
25980
25980
47243
answer