C++のクラスの継承について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Kinesin

C++のクラスの継承について

#1

投稿記事 by Kinesin » 6年前

ここを使うのは初めてなので、テンプレに沿って話します。

[1] 質問文
 [1.1] 自分が今行いたい事は何か
 >>> 新・ゲームプログラミングの館の「sp6章 メニュー画面の作り方(C++編)」(http://dixq.net/g/sp_06.html) に「3.3章 簡単な選択画面を作る」(http://dixq.net/g/03_03.html)の機能を追加したい。

 [1.2] どのように取り組んだか(プログラムコードがある場合記載)
 >>> まず、前提として先ほどリンクを貼った、「sp6章 メニュー画面の作り方(C++編)」(http://dixq.net/g/sp_06.html)のファイルが全て作成済みです。
(もし見るのが面倒な場合は、こちらからzipファイルでダウンロードできるようです。)(http://dixq.net/g/zip/MenuTest4.zip)

それに加えて、とりあえず、Keyboard.hとKeyboard.cppを作成し、Keyboardクラスを作成しました。

コード:

// Keyboard.h
#pragma once

class Keyboard {
public:
     virtual Keyboard::~Keyboard() = 0;
     virtual int getKeyState() = 0;
protected:
     int Key[256];
};

コード:

//Keyboard.cpp

#include "Keyboard.h"
Keyboard::~Keyboard(){} 
 >>> そして、Menu.hの中にメニュー用の構造体を作成し、MenuクラスにKeyboardクラスを継承して、getKeyStateをオーバーライドしました。

コード:

// Menu.h
#pragma once

#include "BaseScene.h"
#include "ISceneChanger.h"
#include "Keyboard.h"

typedef struct {
    int x;
    int y;
    char name[128];
}MenuElement;

class Menu : public BaseScene, Keyboard {
public:
    Menu::Menu(ISceneChanger* changer);
    void Initialize() override;
    //void Finalize() override;
    void Update() override;
    void Draw() override;

    int getKeyState() override;
};

コード:

// Menu.cpp

#include "Menu.h"
#include "DxLib.h"

MenuElement MenuE[3] = {
    {100, 100, "GAME"},
    {100, 150, "CONFIG"},
    {100, 200, "END"},
};
int selectNum = 0;

Menu::Menu(ISceneChanger* changer) :
    BaseScene(changer) {
}

void Menu::Initialize() {
    mImageHandle = LoadGraph("img/Menu.png");
}

void Menu::Update() {

    if (Key[KEY_INPUT_DOWN] == 1) {
        selectNum = (selectNum + 1) % 3;

        for (int i = 0; i < 3; i++) {
            if (i == selectNum) {
                MenuE[i].x = 80;
            }
            else {
                MenuE[i].x = 100;
            }
        }
    }

    if (Key[KEY_INPUT_UP] == 1) {
        selectNum = (selectNum + 4) % 3;

        for (int i = 0; i < 3; i++) {
            if (i == selectNum) {
                MenuE[i].x = 80;
            }
            else {
                MenuE[i].x = 100;
            }
        }
    }

    /*
    if (Key[KEY_INPUT_C] != 0 ) {
        mSceneChanger->ChangeScene(eScene_Config);
    }
    else if (CheckHitKey(KEY_INPUT_G) != 0) {
        mSceneChanger->ChangeScene(eScene_Game);
    }
    */
}

void Menu::Draw() {
    BaseScene::Draw();
    DrawString(0, 0, "CキーでConfig,Gキーでゲーム画面,Escキーでアプリケーションを終了します", GetColor(255, 255, 255));
    DrawString(0, 20, "ここはメニュー画面です", GetColor(255, 255, 255));
    for (int i = 0; i < 3; i++) {
        DrawFormatString(MenuE[i].x, MenuE[i].y, GetColor(255, 255, 255), MenuE[i].name);
    }
}

int Menu::getKeyState()
{
    char tmpKey[256];
    GetHitKeyStateAll(tmpKey);
    for (int i = 0; i < 256; i++) {
        if (tmpKey[i] != 0) {
            Key[i]++;
        }
        else {
            Key[i] = 0;
        }
    }
    return 0;
}
 

 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載) && [1.4] 今何がわからないのか、知りたいのか

 >>> その後、Main.cppでgetKeyStateメソッドを使用しようとすると、
「SceneManagerクラスにはgetKeyStateメンバがありません」と言われます。
しかし、SceneManagerクラスにgetKeyStateを追加した際の継承がよくわかりません。
そこで、

・どのようにgetKeyStateをSceneManagerクラスに追加すれば良いのか

を教えていただきたいです。

コード:

// Main.cpp

#include "DxLib.h"
#include "SceneManager.h"

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
    ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);

    SceneManager sceneManager;
    sceneManager.Initialize();

    while (ProcessMessage() == 0 && ScreenFlip() == 0 && ClearDrawScreen() == 0 && sceneManager.getKeyState()) {
        sceneManager.Update();
        sceneManager.Draw();
    }

    sceneManager.Finalize();

    DxLib_End();
    return 0;
}

[2] 環境  
 [2.1] OS : Windows, Linux等々
 >>> virtaulBox上の仮想環境でWindows10使ってます。

 [2.2] コンパイラ名 : VC++ 2008EE, Borand C++, gcc等々
 >>> 調べ方がよくわかりません……
  ただ、今使用しているIDEはVisual Studio 2017 communityです。

[3] その他
 ・どの程度C言語を理解しているか
 >>> C++は今年の春に始めたばかりなので、正直よくわかってないです。
   ただ、基本的な文字列の扱いやポインタ、アドレスなどは理解してます。

 ・ライブラリを使っている場合は何を使っているか
 >>> Dxライブラリを使用してます。

長文、乱文で申し訳ないです。
私自身で見直しはしましたが、伝わりにくいところがあると思うので、
そこは聞いていただけるとありがたいです。

よろしくお願いします。

アバター
usao
記事: 1887
登録日時: 11年前

Re: C++のクラスの継承について

#2

投稿記事 by usao » 6年前

> Keyboardクラスを作成しました。

(コレ,一体何のためにあるんだろう…? と思うけど,本題じゃないので,よいとして…)
 ↓

> MenuクラスにKeyboardクラスを継承して、getKeyStateをオーバーライドしました。

(ちょっと変な方向の話には見えるけども,これも本題じゃないので,よいとして…)
 ↓

> 「SceneManagerクラスにはgetKeyStateメンバがありません」と言われます。

???

「getKeyState()がMenuクラスにあること」
がSeceneManagerクラスとは全然関係ない事柄であるように見えますが…?



> ・どのようにgetKeyStateをSceneManagerクラスに追加すれば良いのか

そういう名前のメソッドをクラスに追加したいのだとして,
普通にメソッドを追加するのではいけない理由は何なのでしょうか?

Kinesin

Re: C++のクラスの継承について

#3

投稿記事 by Kinesin » 6年前

usaoさん、返信ありがとうございます!

>「getKeyState()がMenuクラスにあること」
>がSeceneManagerクラスとは全然関係ない事柄であるように見えますが…?

そうだったんですか!
SceneManagerクラスを定義したSceneManager.cppでMenu.hをincludeしているので、
そこで繋がっていると思っていたのですが、違ったという事ですよね?

> ・どのようにgetKeyStateをSceneManagerクラスに追加すれば良いのか
>>そういう名前のメソッドをクラスに追加したいのだとして,
>>普通にメソッドを追加するのではいけない理由は何なのでしょうか?

結論から言えば、やってみたのですが無理だったからです。
SceneManagerクラスは構造的に、
SceneManager>>Task>>BaseScene>>Menu>>Keyboard
という立ち位置になっている筈です。
(間違っていたらすみません。m(._.)m)
ここで、Keyboardクラスに仮装関数virtual int getKeyState()を置いて、
Menu,BaseScene,Task,SceneManagerの順でオーバーライドしてみたんです。
しかし、何故かTaskまではgetKeyStateが使えるのに、
SceneManagerで急に使えなくなってしまったので、この方法では無理なんだなと思った次第です。

usaoさんの仰る「普通にメソッドを作る」というのが、この方法では無いのでしょうか?

アバター
usao
記事: 1887
登録日時: 11年前

Re: C++のクラスの継承について

#4

投稿記事 by usao » 6年前

やたら巨大なzipをDLして見た感じ,
継承関係が

SceneMgr
 → ISceneChanger
 → Task

Menu
 → BaseScene → Task

という形になっていて,
MenuとSceneMgrは別系統に見えます.

このMenuに追加で何かを継承させたとしても,SceneMgrには全く影響が無いのではないでしょうか.
SceneMgrは単にシーンに処理を委譲しているだけです.
(つまり,SceneMgrにはgetKeyState()というメソッドは存在しないのだから,呼べるわけがない.)

継承とincludeとかがごっちゃになってるようなら,要復習でしょう.


クラスに普通にメソッドを書くというのは,本当にそのままの意味です.

コード:

class A
{
public:
  //メソッド
  void TheBrandNewMethod()
  {
    所望の処理
  }
};

Kinesin

Re: C++のクラスの継承について

#5

投稿記事 by Kinesin » 6年前

返信が遅くなってしまい、申し訳ありません。

>>やたら巨大なzipをDLして見た感じ,
>>継承関係が

>>SceneMgr
>> → ISceneChanger
>> → Task

>>Menu
>> → BaseScene → Task

>>という形になっていて,
>>MenuとSceneMgrは別系統に見えます.

>>このMenuに追加で何かを継承させたとしても,SceneMgrには全く影響が無いのではないでしょうか.
>>SceneMgrは単にシーンに処理を委譲しているだけです.
>>(つまり,SceneMgrにはgetKeyState()というメソッドは存在しないのだから,呼べるわけがない.)

>>継承とincludeとかがごっちゃになってるようなら,要復習でしょう.
そうだったんですか……
usaoさんの仰る通り、もう一度学ぶ必要がありそうです。
それで色々と調べてみたのですが、このサイト(https://teratail.com/questions/38634)
を見てみて、多少は理解が深まったかなという感じです。
ただ、このサイトのベストアンサーの方が回答されているのを見るだけでは、継承とincludeの違いがイマイチわかりませんでした……
こういう時は、タイトルを変えてもう一度質問し直した方が良いのでしょうか?


>>クラスに普通にメソッドを書くというのは,本当にそのままの意味です.
先ほどのサイトのベストアンサーを参考にしてincludeするものと継承するものを書いてみたのですが、どちらも上手く動きません……
(問題のコードは、どちらもヘッダファイルに全て書きました)

コード:

// includeするもの

#pragma once

#include "BaseScene.h"
#include "ISceneChanger.h"
#include "Keyboard.h"

class SceneManager : public Task, ISceneChanger{
public:
    SceneManager();
    void Initialize() override;
    void Finalize() override;
    void Update() override;
    void Draw() override;

    int getKState() {
        return Keyboard.getKeystate();
    }
    void ChangeScene(eScene NextScene) override;

private:
    BaseScene* mScene;
    eScene mNextScene;
};
こちらのincludeした方のコードは、Keyboardの所に警告文が出て、
「型名は使用できません」という風に書かれています。

コード:

//継承するもの

#pragma once

#include "BaseScene.h"
#include "ISceneChanger.h"
#include "Keyboard.h"

class SceneManager : public Task, ISceneChanger, Keyboard{
public:
    SceneManager();
    void Initialize() override;
    void Finalize() override;
    void Update() override;
    void Draw() override;

    int getKState() {
        return getKeystate();
    }
    void ChangeScene(eScene NextScene) override;

private:
    BaseScene* mScene;
    eScene mNextScene;
};

もう片方の継承のコードでは、
「識別子getKeyStateが定義されていません」
という風に書かれています。

これらのエラーが出てしまうのは、
私のincludeと継承の理解が浅いことが原因なのでしょうが、
どこをどう直せば良いのかご指摘いただければ幸いです。

アバター
usao
記事: 1887
登録日時: 11年前

Re: C++のクラスの継承について

#6

投稿記事 by usao » 6年前

> 継承とincludeの違い

うーん,違い…というか,そもそも全くの別物だと思うのです.
「インド象と巨峰って何が違いますか?」みたいな感じです.

・includeって書いたらどうなる?
・継承したらどうなる?

をそれぞれ,別々にチェックしたほうが良さそうに感じます.

こういった事柄の説明は検索すればたくさん見つかると思います.
例えばincludeなら
http://www7b.biglobe.ne.jp/~robe/cpphtm ... 01027.html
とか.

Kinesin

Re: C++のクラスの継承について

#7

投稿記事 by Kinesin » 6年前

usaoさん、またまた返信ありがとうございます!


>うーん,違い…というか,そもそも全くの別物だと思うのです.
>「インド象と巨峰って何が違いますか?」みたいな感じです.

>・includeって書いたらどうなる?
>・継承したらどうなる?

>をそれぞれ,別々にチェックしたほうが良さそうに感じます.

>こういった事柄の説明は検索すればたくさん見つかると思います.
>例えばincludeなら
>http://www7b.biglobe.ne.jp/~robe/cpphtm ... 01027.html
>とか.

usaoさんの紹介されたサイトは、内容が非常に濃いですね!
第2部を20章まで読んでみたのですが、クラスの継承以前に色々と抜けていることがよく分かりました。
このサイトを一通り読んでみて、それでも分からなければまた伺いたいと思います。

色々とありがとうございました!

Kinesin

Re: C++のクラスの継承について

#8

投稿記事 by Kinesin » 6年前

先日の質問の後に復習して、なんとかエラーなく実行できるようになりました!

Keyboardクラスを抽象クラスにして、
このクラスを使うところでメソッドをオーバーライドしてあげればよかったんですね!

クラスの継承、インクルードについても前よりははるかに理解が深まったと思います。
ありがとうございました。

返信

“C言語何でも質問掲示板” へ戻る