在我的课程中,我需要保留一个指向结构的指针,该结构在我用来实现它的库中定义。由于此库仅在实现文件中使用,因此我希望避免将其直接包含在头文件中。同时我想避免污染命名空间。我想这样做:
/* HEADER */
class Foo {
private:
struct ImplementationDetail;
ImplementationDetail * p;
};
/* SOURCE */
#include <Library.h>
using Foo::ImplementationDetail = Library::SomeStruct;
但这不起作用,我现在正在回归PIMPL:
/* HEADER */
class Foo {
private:
struct ImplementationDetail;
ImplementationDetail * p_;
};
/* SOURCE */
#include <Library.h>
struct ImplementationDetail {
Library::SomeStruct * realp_;
}
有没有办法避免双重解除引用?由于未知指针大小,我的非工作第一解决方案的原因是什么?
答案 0 :(得分:1)
// Header
class Foo {
private:
struct ImplementationDetail;
ImplementationDetail * p;
};
// Source
#include <Library.h>
struct Foo::ImplementationDetail :public Library::SomeStruct {
// ....
};
并且在此源文件中分配/解除分配/解除引用指针应该只能正常工作。
答案 1 :(得分:0)
这是一个不正确的声明:
using Foo::ImplementationDetail = Library::SomeStruct;
using
无法正常工作。在C ++ 11中,using
无法为一个名称空间中的名称创建另一名称空间中名称的别名。在C ++ 03中,所有using
都会在当前翻译单元中将一些其他命名空间带入全局可见性。它不是用来在C ++ 03中创建别名,因为你似乎想在这里做。
pimpl 是执行您要执行的操作的事实上的方法,但是在您的头文件中而不是尝试使用ImplementationDetail*
,我会使用简单{ {1}}。根据标准,以这种方式使用void*
保证是正确的:
void*
使用class Foo {
private:
void * pImpl;
2 从static_cast
转到您的实际类型:
void*
您可以通过向前声明库类型来避免以一致的方式使用void Foo::Bar()
{
Library::SomeStruct* thingy = static_cast <Library::SomeStruct*> (pImpl);
// ...
}
:
void*
然后在实施中不需要丑陋的演员阵容。
2 使用namespace Library
{
struct SomeStruct;
};
class Foo
{
private:
Library::SomeStruct* pStruct;
};
:或static_cast
答案 2 :(得分:0)
你不能采取第一种方法的原因是在标题中你告诉编译器“我在Foo
中声明了一个嵌套类,它被称为ImplementationDetail
”。然后你继续说“等待等待,它不是一个新的类,它完全是另一个别的东西”,可以理解编译器会感到困惑。
您是否曾尝试过声明库的实现并使用它而不是尝试创建别名?
答案 3 :(得分:0)
在您的第一个代码中,您将嵌套类型ImplementationDetail
声明为struct
,它将在Foo
内定义。尝试别名它不起作用,因为这将是其他地方定义的类型,实际上,您无法从类外部访问private
结构。将指针包装到内部的另一个对象似乎是不必要的:您可以改为按值嵌入Library::SomeStruct
或从ImplementationDetail
导出Library::SomeStruct
:
struct ImplementationDetail
: Library::SomeStruct {
using Library::SomeStruct::SomeStruct;
};
(using
声明仅用于从Library::SomeStruct
继承所有构造函数。)
答案 4 :(得分:0)
我认为如果没有施法,这是不可能的。
基本上有两种方法可以做到:
1)将p_定义为void*
并将其投射到使用它的每个函数中。
/* HEADER */
class Foo {
private:
void* p;
};
/* SOURCE */
#include <Library.h>
void Foo::AnyFunc()
{
Library::SomeStruct* pImpl = reinterpret_cast<Library::SomeStruct*>(p);
...
}
2)创建一个类的“阴影”类(在.cpp文件中),克隆所有成员并将p_定义为Library :: SomeStruct。然后将this
指针强制转换为此阴影类。这当然是一个非常不安全和肮脏的黑客,我不建议......
/* HEADER */
class Foo {
private:
void* p;
};
/* SOURCE */
#include <Library.h>
class FooImpl
{
public:
void AnyFunc() { p->DoSomething(); }
private:
Library::SomeStruct* p;
}
void Foo::AnyFunc()
{
FooImpl* pImpl = reinterpret_cast<FooImpl*>(this);
pImpl->AnyFunc();
}
这会利用内存结构,因此非常脆弱(所有成员需要按相同的顺序排列,当您添加或删除成员时,您也需要更新ShadowFoo)。我提到这只是为了完整。
3)这将我们带到另一个但更简单的方法:在源文件中创建实现并使用void*
在指针构建器中初始化它: -
/* HEADER */
class Foo {
private:
void* p;
};
/* SOURCE */
#include <Library.h>
class FooImpl
{
public:
FooImpl(void* pSomeStruct)
{
p = reinterpret_cast<Library::SomeStruct*>(pSomeStruct);
}
void AnyFunc() { p->DoSomething(); }
private:
Library::SomeStruct* p;
}
void Foo::AnyFunc()
{
FooImpl impl = FooImpl(p);
impl.AnyFunc();
}