这里有比朋友课更好的方法吗
Is there a better way than friend classes here?
在C++for Windows中编程,尽管这种情况可能在任何地方出现。这是我的问题的简化版本,以使问题易于管理,因此不要过于关注细节:)
我有一个类class Window
,它包含一个windows HWND
数据项。我想完全封装HWND
,这样类的用户就必须遍历该类才能对该窗口执行任何操作,所以它存储在一个私有成员变量中。我不想为它提供任何公共的"getter",因为这会破坏允许用户绕过我的类的封装。
现在我想创建一个类class Direct3d11
来封装一些directx api。为了创建这个类的实例,它需要窗口的HWND,所以我在它的构造函数中向它传递一个Window
对象。
class Direct3D11
{
public:
Direct3D11(const Window& window);
};
在构造函数内部,它可以访问窗口对象,但是它需要包含在其中的HWND,以便能够物理地创建Direct3D11类将管理的窗口对象,但它无法获得该信息。
我可以添加一个私有的getter函数来将HWND添加到Window类中,然后将Direct3D11类作为Window的朋友类,以便它调用该函数。
然而,这似乎不是很优雅,尤其是因为Window类在其他方面根本不需要知道任何关于Direct3D11类的信息。
我是否错过了实现这一目标的更好方法?Friend类没有吸引力,拥有公共getter函数也没有多大吸引力。
您可以在Window
中创建Direct3D11
类,因为Windows
拥有HWND
。
大致如下:
class Window
{
HWND hwnd;
Direct3D11 d;
public:
Window() : d(hwnd) {}
Direct3D11& getDirect3D()
{
return d;
}
}
在您的情况下,我建议为HWND
提供一个getter,因为您可能会更频繁地需要它。提供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);
}
};
您可能在Window上有一个名为Execute的函数。它将接收一个std::函数,该函数带有HWND的占位符作为参数。然后,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
如果您愿意使用friend关键字,您可以确保window不知道需要hwnd的类。只需创建类(该窗口和DirectX从中继承)即可为您处理操作。这使您能够解决DirectX的问题,并在下次出现时进行处理。
侧栏:朋友不是一个四个字母的词。如果使用合理,Friend实际上是向C++的访问控制添加分级的好方法(public、Friend(当处于受保护状态时)、protected、Friend、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
- 初始化具有非默认构造函数的std::数组项的更好方法
- 寻找一种更好的方法来表示无符号字符数组
- 哪种方法更好,性能明智
- 有没有更好的方法来处理异常? try-catch块真的很丑
- 有没有更好的方法对C++中的三个整数进行排序?
- Protobuf中重复字段的问题.使用重复字段进行序列化/反序列化的更好方法是什么?
- 编写按初始值循环的循环的更好方法是什么
- 更好的方法,而不是在C ++中使用cin.ignore
- 用 c++ 为游戏制作"bullet"的更好方法?
- 在类的第一个/最后一个实例存在之前/之后调用一对函数.有没有更好的方法?
- 做一个unordered_multimap键的平均值是更好的方法吗?
- 有没有更好的方法可以使用特征/C++实现 matlab 的逻辑索引?
- 在CMakeLists中包含目录的更好方法.txt
- 有没有更好的方法来为C++写这个?
- 有没有更好的方法来编写这个c++代码
- 将QDomDocument数据用作文本的更好方法
- 有没有更好的方法可以让我接收这些输入?C++
- C++ - 创建具有相同字符的特定大小的以 null 结尾的 c 样式字符串的更好方法
- 哪种方法更好获取静态链接DLL的模块句柄(HMODULE) - 使用GetModuleHandleEx()或LoadLibrary()?
- 静态常量成员值与成员枚举:哪种方法更好以及为什么?