44550


  1. 「//////」コメント部の場所なのですが、Clockのポインタ変数には new clock,  
new LaughClock 両方できて、なぜ逆のことであるLaughClockのポインタ変数では、new Clockができないのか理由を知りたいです。

  2. また、DoAciton(Clock* pclock)の部分ですが、なぜクラス型の違うポインタを受け取っても実行されるのでしょうか？教えていただけますでしょうか。

[code]

    #include <iostream>
    using namespace std;
    
    class Clock{
    
        public:
    
        void Tick(){
            Action();
        }
    
        virtual void Action()
        {
            cout<<"Clock class \n";
        }
    
        void test(){
            cout<<"test Clock\n";
        }
    
    };
    
    class LaughClock : public Clock
    {
    
        public:
    
        virtual void Action()
        {
            cout<<"Laugh Clock\n";
        }
    
        void test(){
            cout<<"test Laugh \n";
        }
    
    };
    
     void DoAction(Clock* pclock)
    {
        pclock->Action();
    }
    
    void TestVirual()
    {
        Clock pee;
        pee.Action();
    
        LaughClock keta;
        keta.Action();
    
        DoAction(&pee);//////////
        DoAction(&keta);/////////
    
    }
    
    int main(){
    
        LaughClock *a;
        a = new LaughClock();
        a->test();
    
        LaughClock *aa;
        aa = new LaughClock();/////////////ここです。
        //aa = new Clock();
        aa->test();
    
        Clock *b = new Clock;
        b->test();
    
        Clock *bb;
        bb = new LaughClock();
        bb->test();
    
        Clock x;
        x.Tick();
    
        LaughClock xx;
        xx.Tick();
    
        estVirtual();
    
        return 0;
    }
    
[/code]


CC BY-SA 4.0
2018-06-06T02:08:53.500
44546
2018-06-06T03:00:36.310
2018-06-06T02:53:28.747
4236
question
c++
継承、仮想関数があるクラスのポインタ変数について


[継承](https://ja.wikipedia.org/wiki/%E7%B6%99%E6%89%BF_\(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0\))とはオブジェクト指向を構成する概念の一つです。続けて引用します。

> BがAを継承する場合、B is a A. （BはAの一種である）という意味的な関係（Is-a関係）が成り立つ。

と説明されている通りで、質問の例では `LaughClock` が `Clock` を継承しているため `LaughClock` は `Clock`
の一種であると言えます。そのため `LaughClock` から `Clock` への変換は可能です。しかし逆は成立しないため `Clock` から
`LaughClock` への変換はできません。

* * *

>   1. Clockのポインタ変数には new clock, new LaughClock
> 両方できて、なぜ逆のことである。LaughClockのポインタ変数では、new Clockができないのか
>

上記の通り、`LaughClock` は `Clock` の一種であり、`Clock` は `LaughClock` の一種でないからです。

>   2. DoAciton(Clock* pclock)の部分ですが、なぜクラス型の違うポインタを受け取っても  
>  実行されるのでしょうか
>

上記の通り、`LaughClock` は `Clock` の一種だからです。

C++言語では[dynamic_cast](https://en.cppreference.com/w/cpp/language/dynamic_cast)を行うことで
`Clock` から `LaughClock` への変換を試みることができます。もし変換できなかった場合は実行時に `std::bad_cast`
例外が投げられます。


CC BY-SA 4.0
2018-06-06T02:44:49.420
44549
2018-06-06T02:44:49.420
4236
44546
answer


そこは継承・派生機構の基礎中の基礎というか、技術論というより概念理解なので、本人がどう納得するか次第なところです。たとえ話をしてもよいのだけど、深い理解に至るにはその最初のたとえ話が邪魔立ったりする箇所です。

提示例に従うなら  
\- `Clock` とは時計一般（およそ時計ならなんでも `Clock` ）  
\- `LaughClock` とは時計であって、特に笑う時計

ということは数学的には `LaughClock` ⊂ `Clock` つまり `LaughClock` は `Clock`
の部分集合と表記できます。普通に日本語で書けば `LaughClock` は `Clock` の一種。

A1.

  * `Clock* c = new LaughClock();` ができる理由

`LaughClock` であるものは必ず `Clock` だから。

  * `LaughClock* d = new Clock();` ができない理由

`Clock` であるものは `LaughClock` だとは限らないから。

ここんところはちょっとわかりにくいですね。下記のような状況を想定すると

[code]

    class SobClock : public Clock { ... };
    
[/code]

上記 `LaughClock` と `SobClock`
は別な物であるとわかりますか？（共通なところもあるので「まるっきり別物」ではないが、同じに扱うことはできません）これが納得できるなら

[code]

    Clock* c = new SobClock(); // 問題ない
    LaughClock* d = c; // できない
    
[/code]

上記 `d=c;` ができてしまうとまずい、ということも理解できると思います。（これができてはならない、と理解するのが肝だったりします）。

なのでコンパイラはこのような初期化や代入を禁じています。その判断基準は「型の継承関係」だけという仕様なので、右辺が `new Clock()`
であってもエラーになります。

派生先の型へのポインタから基底型へのポインタに変換すること＝ＯＫ（仕様上必ずできる）  
基底型へのポインタから派生先の型へのポインタに変換すること＝ＮＧ（できるとは限らない）

後者の変換ができる（した結果問題が無い）場合もありますが、この変換のためにはキャストを明示する必要があります。

A2. 実は A1. とまったく同じ。

`Clock` であるものならば、必ず `Action()` できる。  
`LaughClock` であるものは `Clock` でもあるから以下同文。


CC BY-SA 4.0
2018-06-06T03:00:36.310
44550
2018-06-06T03:00:36.310
8589
44546
answer