让我们说我想制作一些应该支持加载图形Image
的引擎,所以我有
struct Image;
Image* load_image_from_file(...);
我不希望外部世界知道Image
究竟是什么,他们只会处理指向它的指针。
但是在engine
内,我想使用特定类型,例如SDL_Surface
在SDL中完全定义。
我可以以某种方式重新映射此文件的Image,以便编译器在每次看到SDL_Surface*
(除宏之外)时都假定为Image*
吗?
即。我想要像typedef struct SDL_Surface Image;
所有尝试都是
using Image = SDL_Surface;
typedef SDL_Surface Image;
typedef struct SDL_Surface Image;
产生编译时错误(http://codepad.org/1cFn18oh)。
我知道我可以在struct Image{SDL_Surface* surface};
/ engine.c
中使用engine.cpp
之类的内容,但会创建不必要的间接内容,我必须输入->surface
。
另一个肮脏的解决方案是使用显式强制转换,例如((SDL_Surface*)image)
,但我更清楚地重命名。
PS。我对C和C ++的答案感兴趣。
答案 0 :(得分:3)
只需定义别名:
using Image = SDL_Surface;
typedef SDL_Surface Image;
which compiles就好了。
如果您需要隐藏SDL_Surface
,只需将其导入某个匿名或detail
命名的命名空间,并将其用作this。
如果由于某些原因,您想要定义自己的Image
类型,则可以始终声明一个(n)(隐式)转换函数/运算符,如:
struct Image {
/* explicit */ operator SDL_Surface() const;
// ...
};
如果您需要,还可以返回Image
:
struct Image {
/* explicit */ Image(SDL_Surface&&);
/* explicit */ Image(SDL_Surface const&);
// ...
};
答案 1 :(得分:1)
在C ++ 中,您可以使用继承:
// User view
struct Image; // forward declaration (inclomplete type).
Image* LoadFromFile (...); // You can use pointer to incomplete type
// Implementation view
struct Image: SDL_Surface { }; // here you go !! :-)
备注:使用类和私有继承会更安全,因此只有Image知道它是SDL_Surface。
在某些情况下,从现有的实现类继承可能是不可取的(例如,如果您需要虚拟析构函数而基类不需要)。然后PIMPL idiom可能是另一种选择(以额外的间接为代价):
//User View unchanged
struct Image;
int TestImage(Image*z);
//implementation view
struct Image {
struct ImageImpl { int x; }; // nested definition or typedef or whatever
ImageImpl *p; // works in every case, at cost of an extra indirection instead of a pointer
};
int TestImage(Image* z)
{
return z->p->x;
}
这里PIMPL的主要优点是,您可以展示的不仅仅是不完整的类型,因此为客户提供了一些有用的成员函数。但是如果你不需要这个,并且因为你已经与poitners一起使用客户端的对象,你也可以直接进入组合并拥有ImageImpl
成员而不是PIMPL指针。
在C 中,您无法使用继承。但是组合肯定会成功:
struct Image {
SDL_Surface s;
};
答案 2 :(得分:1)
此类操作通常使用PIMPL(指向实现的指针)模式完成。但是如果你现在想要避免间接,或者类型是不完整的(这不是SDL_Surface
的情况,但它与许多其他SDL类一样)你可以使用指向{{1}的指针因为它可以指向任何数据,然后将其强制转换为实现方。
在此,我们使用void
来使用Rule of Zero。这样的std::unique_ptr
现在是不可复制的,但可以移动。如果你想复制它,请使用类似Image
的指针(不在标准中,但你可以自己轻松编写这样的指针或使用第三方指针)
value_ptr
答案 3 :(得分:0)
如果您的客户端代码对图像没有任何作用,除了传递指针之外,您可以使用Windows API技巧:
each()
答案 4 :(得分:0)
在C 中,您可以采用不完整的类型。
因此,您可以在头文件中定义API:
myapi.h
struct Image;
struct Image* load_image_from_file(...);
...
请注意,您的struct Image
类型虽然可供您的客户使用,但却完全对其隐藏。
现在,您的实现完成了结构的完整声明:
myapi.c:
struct Image {
/* whatever you want to put here */
/* even SDL_Surface */
/* or pointer to it */
};
/* function bodies */
将已编译的C代码(对象,静态或动态库)和标头捆绑到客户端。
答案 5 :(得分:0)
在导出的标题中,您可以转发SDL_Surface
然后声明Image
是指向它的指针。像:
struct SDL_Surface;
typedef SDL_Surface* Image;
extern Image load_image_from_file(char*);
这样您的库可以在没有SDL标题的情况下使用 但是,仍然需要SDL.dll。