#pragma twice

KAB-studio > プログラミング > #pragma twice > 362 Version 17.07 継承と代入・ポインタの場合

#pragma twice 362 Version 17.07 継承と代入・ポインタの場合

前のページへ 表紙・目次へ 次のページへ

 Version 17.07
継承と代入・ポインタの場合

前回は、継承関係にあるクラスの代入について説明しました
つまりこういうことだったよね

○基本クラス←派生クラスの代入
×派生クラス←基本クラスの代入

そういうこと。で、今回は似てるようで全く違う、ポインタの場合の話を
説明します
ポインタの場合の、継承と代入の関係ってこと?
そういうこと。似てるけど全然違う話だから、頭切り替えた方がいいか

そこまで言うってことはかなり複雑なんだ……
まず、使用するのは前回と同じ CData クラスと CDerivedData クラス。
それぞれ m_iData メンバ変数と m_iData2 メンバ変数を持っています
その方が分かりやすいね
まず、結論から言うと、基本的にはポインタの場合も以下のルールが適用
されます

○基本クラス←派生クラスの代入
×派生クラス←基本クラスの代入

ポインタじゃない時と同じなんだ。それなのに複雑
そう、その仕組みが複雑で、場合によっては〈派生クラス←基本クラス〉
が可能だから
げ、それは複雑だ
ま、その前に基本的な部分から

○基本クラス←派生クラスの代入

// Main.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // CDerivedData クラスを用意します。
    CDerivedData cDerivedData;
    cDerivedData.m_iData = 100;
    cDerivedData.m_iData2 = 200;

    // CData クラスのポインタを用意して代入します。
    CData *pcData;
    pcData = &cDerivedData;

    // 出力します。
    char pch[256];
    sprintf( pch, "%d\n", pcData->m_iData );
    OutputDebugString( pch );
    // 100

    return 0;
}

ここが代入してるところだね

    pcData = &cDerivedData;

このように、派生クラスのアドレスを基本クラスのポインタに代入する
ことができます
で、それを出力するとちゃんと代入できてます、と
で、逆は不可です

×派生クラス←基本クラスの代入

// Main.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // CData クラスを用意します。
    CData cData;
    cData.m_iData = 100;

    // CDerivedData クラスのポインタを用意して代入します。
    CDerivedData *pcDerivedData;
    pcDerivedData = &cData;
    // コンパイルエラー:
    // error C2440: '=' : 
    //     'class CData *' から 'class CDerivedData *' に変換する
    //     ことはできません。
    //     指示された型は関連がありません; 変換には reinterpret_cast、
    //     C スタイル キャストまたは関数スタイルのキャストが必要です。

    return 0;
}

こっちはここね

    pcDerivedData = &cData;

このように、基本クラスのアドレスを派生クラスのポインタに代入するこ
とはできません
ここまでは前回と同じね
ところが、こんなことができてしまうんです

// Main.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // CDerivedData クラスを用意します。
    CDerivedData cDerivedData;
    cDerivedData.m_iData = 100;
    cDerivedData.m_iData2 = 200;

    // CData クラスのポインタを用意して代入します。
    CData *pcData;
    pcData = &cDerivedData;

    // CDerivedData クラスのポインタを用意して代入します。
    CDerivedData *pcDerivedData;
    pcDerivedData = (CDerivedData *)pcData;

    // 出力します。
    char pch[256];
    sprintf
        ( pch
        , "%d, %d\n"
        , pcDerivedData->m_iData 
        , pcDerivedData->m_iData2
        );
    OutputDebugString( pch );
    // 100, 200

    return 0;
}

……ちょ、ちょっと待った!! これおかしいって! だって

    pcData = &cDerivedData;

ここで CData クラスになってるんだから、 m_iData だけ代入されて、
m_iData2 は代入されないじゃん。で、

    pcDerivedData = (CDerivedData *)pcData;

ここで CData クラスから CDerivedData クラスにキャストしてるけど、
ってゆーか前回キャストできないって言ってたのにできてるけど、ともかく
pcData には m_iData2 がないから pcDerivedData に m_iData2 が渡される
はずないのに

        , pcDerivedData->m_iData 
        , pcDerivedData->m_iData2
        );
    OutputDebugString( pch );
    // 100, 200

出力できてるし! ありえねー!!
ここが重要な点。つまり、前回の代入とは仕組みが違うってこと
……どういうこと?
というわけで次回に続く!

/*
    Preview Next Story!
*/
わけわかんないし!!
ま、まったく別って考えるといいんだけどね
えー? でもキャストは同じだし
似てるだけ似てるだけ
えー???
というわけで次回
< Version 17.08 アップキャストとダウンキャスト >
につづく!
ポインタの世界は、普通の世界と違うんです
納得いかねー!!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。