1

この状況はどこでも発生する可能性がありますが、Windows 用の C++ でのプログラミング。これは、質問を管理しやすくするために私の問題を簡略化したものなので、詳細に巻き込まれないでください:)

Windowsデータ項目class Windowを含むクラスがあります。クラスのユーザーがそのウィンドウで操作を実行するためにクラスを通過する必要があるように、それHWNDを完全にカプセル化したいので、プライベートメンバー変数に格納されます。HWNDカプセル化が壊れて、ユーザーがクラスをバイパスできるようになるため、パブリックの「ゲッター」を提供したくありません。

class Direct3d11ここで、directx API の一部をカプセル化するクラスを作成したいと考えています。このクラスのインスタンスを作成するには、ウィンドウの HWND が必要なので、Windowコンストラクターでオブジェクトを渡します。

class Direct3D11
{
public:
    Direct3D11(const Window& window);
};

コンストラクター内ではウィンドウ オブジェクトにアクセスできますが、Direct3D11 クラスが管理するウィンドウ オブジェクトを物理的に作成できるようにするために、内部に含まれる HWND が必要ですが、その情報を取得する方法はありません。

Window クラスに HWND を取得するプライベート ゲッター関数を追加し、Direct3D11 クラスを Window のフレンド クラスにして、関数を呼び出すようにすることができます。

ただし、特にクラス Window はクラス Direct3D11 について何も知る必要がないため、これはあまり洗練されていないように見えます。

これを達成するためのより良い方法がありませんか?フレンド クラスは魅力的ではありません。パブリック ゲッター関数を使用することもあまり魅力的ではありません。

4

4 に答える 4

3

が を所有しているため、 内にDirect3D11クラスを作成できます。WindowWindowsHWND

これらの行に沿ったもの:

class Window
{
    HWND hwnd;
    Direct3D11 d;
public:
    Window() : d(hwnd) {}
    Direct3D11& getDirect3D()
    {
       return d;
    }
}
于 2013-02-04T22:33:48.623 に答える
1

HWNDあなたの場合、おそらくもっと頻繁にそれを必要とするので、私はゲッターを提供することを提案します。ゲッターを提供することは、ウィンドウクラスの責任を負うことを意味するのではなく、ウィンドウのライフサイクルに責任を負います。ユースケースでコードをより使いやすく、簡単に分割できるようにするだけです。

そうは言っても、これがあなたが試すことができるより一般的なアプローチです:

class Window;

class Direct3D {
public:
    void apply(Window &window, HWND hWnd);
};

class Window {
public:
    void accept(Direct3D &direct3d) {
        direct3d.apply(*this, this->m_hWnd);
    }
};
于 2013-02-04T22:50:17.947 に答える
1

friendキーワードを使用する場合は、ウィンドウにhwndを必要とするクラスの知識がないことを確認できます。アクションを処理するクラス(そのウィンドウとDirectXが継承するクラス)を作成するだけです。これにより、DirectXの問題を解決でき、次に問題が発生したときにも問題を解決できます。

Side Rant:友達は4文字の言葉ではありません。フレンドは、合理的に使用されている場合、実際にはC ++のアクセス制御(パブリック、フレンド(保護されている場合)、保護されている、フレンド(プライベートの場合)、プライベート)にグラデーションを追加するための優れた方法です。

#include <iostream>

class HwndOwner;
class HwndWanter
{
protected:
    HwndWanter(){}
    int getHwndFromOwner(HwndOwner & owner);
};

class HwndOwner
{
protected:
    HwndOwner() : hwnd(42){}

private:
    friend class HwndWanter;
    int getHwnd()
    {
        return hwnd;
    }

    int hwnd;
};

class Window : public HwndOwner
{
    //This is not the class you are looking for...
};


class Direct3D : private HwndWanter
{
public:
    Direct3D(HwndOwner & owner)
        : HwndWanter()
    {

        std::cout << getHwndFromOwner(owner) << std::endl;
    }
};

int HwndWanter::getHwndFromOwner(HwndOwner & owner)
{
    return owner.getHwnd();
}

int main()
{
    Window window;
    Direct3D hwndWanter(window);
}

出力:

42
于 2013-02-05T04:15:42.933 に答える
1

おそらく、Execute と呼ばれる Window 上の関数を持つことができます。HWND のプレースホルダーをパラメーターとして std::function を使用します。次に、ウィンドウは、HWND を唯一のパラメーターとして関数を呼び出します。

これには c++11 が必要ですが、コードは次のようになります。

#include <functional>
#include <iostream>

struct Foo {
    explicit Foo(int num) : num_(num) {}
    template<typename T>
    void execute(std::function<T> f) const { f(num_); }
    private:
    int num_;
};

struct Bar{
    void print_nums(int i,int j)
    {
        std::cout << "i:" << i << ", " << "j:" << j << std::endl;
    }
};

int main()
{
    Foo o(42);
    Bar b;

    //the function we want to execute requires an int
    //that Foo knows about
    typedef void myFunction(int);

    // store the result of a call to std::bind
    std::function<myFunction> display_1337_first = std::bind(&Bar::print_nums, b,1337, std::placeholders::_1);
    std::function<myFunction> display_1337_last = std::bind(&Bar::print_nums, b, std::placeholders::_1, 1337);
    o.execute<myFunction>(display_1337_first);
    o.execute<myFunction>(display_1337_last);
    return 0; 
}

//output:
//i:1337, j:42
//i:42, j:1337
于 2013-02-04T22:45:25.137 に答える