我最近遇到了这样的情况:
class A
{
public:
typedef struct/class {...} B;
...
C::D *someField;
}
class C
{
public:
typedef struct/class {...} D;
...
A::B *someField;
}
Run Code Online (Sandbox Code Playgroud)
通常你可以声明一个类名:
class A;
Run Code Online (Sandbox Code Playgroud)
但是你不能转发声明一个嵌套类型,以下导致编译错误.
class C::D;
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
class Namespace::Class;
Run Code Online (Sandbox Code Playgroud)
我为什么要这样做?:
namespace Namespace {
class Class;
}
Run Code Online (Sandbox Code Playgroud)
使用VC++ 8.0,编译器会发出:
错误C2653:'Namespace':不是类或命名空间名称
我假设这里的问题是编译器无法判断Namespace是类还是命名空间?但是为什么这很重要,因为它只是一个前瞻性声明?
是否有另一种方法来转发声明在某个命名空间中定义的类?上面的语法感觉就像我"重新打开"命名空间并扩展其定义.如果Class没有实际定义Namespace怎么办?这会在某个时候导致错误吗?
是否可以转发声明一个嵌套类,然后将其用作外部类的具体(不是指向/引用)数据成员的类型?
IE
class Outer;
class Outer::MaybeThisWay // Error: Outer is undefined
{
};
class Outer
{
MaybeThisWay x;
class MaybeThatOtherWay;
MaybeThatOtherWay y; // Error: MaybeThatOtherWay is undefined
};
Run Code Online (Sandbox Code Playgroud) 我的队友经常使用pimpl的变体,他喜欢这样:
foo.h中:
namespace { struct Impl; }
class Foo
{
public:
Foo();
~Foo();
void Bar(int n);
/* ... */
private:
std::unique_ptr<Impl> _impl;
};
Run Code Online (Sandbox Code Playgroud)
这里发生的事情是他正在声明实现类在匿名命名空间中.然后他将Impl在Foo.cpp中定义类.
因此,结构的定义::Impl将可供Foo.cpp翻译单位使用.其他代码包含Foo.h会引发警告,因为它们显然无法访问::Impl定义的内容Foo.cpp.但是,我们不需要它们 - 它只是一个Foo.cpp只用于它的类; 我们不希望它在其他地方可见或已知.
虽然我们当然可以在.cpp文件中包含多个标题,每个标题都声明自己的::Impl结构,但实际上并没有发生冲突,因为结构永远不会在各自的翻译单元之外使用.
tl; dr:这看起来很奇怪,引发警告,看起来好像会引起冲突,但似乎确实有效.
所有这一切,我不满意我的代码中提出了一些警告,这些警告已经深入到我们的代码中(这个文件越多,它就越难以取出.)这也只是一大堆警告.
我的队友坚持这一点,因为它很简单,保持代码定义简单,并允许我们Impl在所有代码中使用简短,一致的类名.
我不是编码惯例的坚持者; 如果这是我们用例的好习惯,我不介意.但是我觉得这是安全和可维护的,并且在某些时候不会在我们的脸上爆炸.