1

尽管这种情况可能在任何地方出现,但在 Windows 上使用 C++ 编程。这是我的问题的简化版本,以使问题易于管理,因此不要太关注细节:)

我有一个class Window包含 WindowsHWND数据项的类。我想完全封装它,HWND以便类的用户必须通过类才能在该窗口上执行任何操作,因此它存储在私有成员变量中。我不想为它提供任何公共“getter”,因为这会破坏允许用户绕过我的课程的封装。

现在我想创建一个类class Direct3d11来封装一些directx api。为了创建这个类的一个实例,它需要一个窗口的 HWND,所以我Window在它的构造函数中传递了一个对象。

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

在构造函数内部,它可以访问窗口对象,但是它需要包含在其中的 HWND 才能物理地创建 Direct3D11 类将管理的窗口对象,但它无法获取该信息。

我可以添加一个私有 getter 函数来获取 HWND 到 Window 类,然后使 Direct3D11 类成为 Window 的朋友类,以便它调用该函数。

然而,这似乎不是很优雅,尤其是因为 Window 类根本不需要知道关于 Direct3D11 类的任何事情。

我是否错过了实现这一目标的更好方法?朋友类没有吸引力,拥有公共 getter 函数也没有太大吸引力。

4

4 回答 4

3

你可以在里面创建Direct3D11Window,因为Windows拥有HWND.

这些方面的东西:

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

如果你愿意使用friend关键字,你可以确保window不知道需要hwnd的类。只需制作为您处理操作的类(该窗口和 DirectX 继承自)。这使您可以解决 DirectX 的问题,并在下次出现时解决。

Side Rant:朋友不是四个字母的词。Friend,如果使用得当,实际上是为 C++ 的访问控制(public、friend (when in protected)、protected、friend (when in private)、private)添加层次的好方法。

#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

在您的情况下,我建议为 the 提供一个吸气剂,HWND因为您可能会更频繁地需要它。提供 getter 并不意味着您承担 Window 类的责任,它仍然负责窗口的生命周期。你只是让它更有用,更容易在用例中划分你的代码。

也就是说,这是一种更通用的方法,您可以尝试:

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

您可能在 Window 上有一个名为 Execute 的函数。它将接收一个带有 HWND 占位符的 std::function 作为参数。然后,Window 将使用 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 回答