class 之前或 Pimple 习语中的成员之前的 C++ 前向声明?
C++ Forward declaration before class or before member in the Pimple idiom?
大多数 Pimpl 示例如下所示:
更新: 两种情况都失败了,即有和没有命名空间。请参阅 R Sahu 在 的回答。 class Impl 必须使用 class 名称限定 Simpl
// Simple.h
#include <memory>
class Simple {
struct Impl; // WORKS!
std::unique_ptr<Impl> impl_;
public:
Simple();
~Simple();
int get() const;
};
但这在您使用名称空间的现实世界中似乎失败了。
当存在命名空间时,前向声明必须移到 class 声明之前。谁能解释一下为什么?
// Simple.h but now with name spaces
namespace weired::example {
struct Impl; // OK! forwad declaration must go here
class Simple {
//struct Impl; // ERROR! incomplete type in ctor definition
std::unique_ptr<Impl> impl_;
public:
Simple();
~Simple();
int get() const;
};
}
我已经用 gcc9
和 clang8
测试过 -std=c++11
到 c++2a
。
为了完整起见,这里有 Simple.cpp 和 main.cpp 文件,因此您可以自己 运行 这个例子:
// Simple.cpp
#include "Simple.h"
namespace weired::example {
struct Impl {int a,b;};
Simple::Simple() : impl_(new Impl{3,4}) {}
Simple::~Simple() = default;
int Simple::get() const
{
return impl_->a;
}
}
和
// main.cpp
#include "Simple.h"
#include <iostream>
int main () {
auto nonsense = weired::example::Simple{};
std::cout << nonsense.get() << '\n';
}
您可以在 class 内部和 class 外部转发声明 Impl
,无论 Simple
是在命名空间中定义还是全局定义。
Impl
的实现在两种情况下几乎相同。
没有namespace
选项 1(Impl
是同行 class)
.h 文件
struct Impl;
class Simple { ... };
.cpp 文件
// Define Impl
struct Impl { ... };
// Define Simple
选项 2(Impl
是嵌套 class)
.h 文件
class Simple
{
struct Impl;
...
};
.cpp 文件
// Define Impl
struct Simple::Impl { ... }; // Need the Simple:: scope here.
// Define Simple
和namespace
选项 1(Impl
是同行 class)
.h 文件
namespace weired::example {
struct Impl;
class Simple { ... };
}
.cpp 文件
namespace weired::example {
// Define Impl
struct Impl { ... };
// Define Simple
}
选项 2(Impl
是嵌套 class)
.h 文件
namespace weired::example {
class Simple
{
struct Impl;
...
};
}
.cpp 文件
namespace weired::example {
// Define Impl
struct Simple::Impl { ... }; // Need the Simple:: scope here.
// Define Simple
}
大多数 Pimpl 示例如下所示:
更新: 两种情况都失败了,即有和没有命名空间。请参阅 R Sahu 在 Simpl
// Simple.h
#include <memory>
class Simple {
struct Impl; // WORKS!
std::unique_ptr<Impl> impl_;
public:
Simple();
~Simple();
int get() const;
};
但这在您使用名称空间的现实世界中似乎失败了。 当存在命名空间时,前向声明必须移到 class 声明之前。谁能解释一下为什么?
// Simple.h but now with name spaces
namespace weired::example {
struct Impl; // OK! forwad declaration must go here
class Simple {
//struct Impl; // ERROR! incomplete type in ctor definition
std::unique_ptr<Impl> impl_;
public:
Simple();
~Simple();
int get() const;
};
}
我已经用 gcc9
和 clang8
测试过 -std=c++11
到 c++2a
。
为了完整起见,这里有 Simple.cpp 和 main.cpp 文件,因此您可以自己 运行 这个例子:
// Simple.cpp
#include "Simple.h"
namespace weired::example {
struct Impl {int a,b;};
Simple::Simple() : impl_(new Impl{3,4}) {}
Simple::~Simple() = default;
int Simple::get() const
{
return impl_->a;
}
}
和
// main.cpp
#include "Simple.h"
#include <iostream>
int main () {
auto nonsense = weired::example::Simple{};
std::cout << nonsense.get() << '\n';
}
您可以在 class 内部和 class 外部转发声明 Impl
,无论 Simple
是在命名空间中定义还是全局定义。
Impl
的实现在两种情况下几乎相同。
没有namespace
选项 1(Impl
是同行 class)
.h 文件
struct Impl;
class Simple { ... };
.cpp 文件
// Define Impl
struct Impl { ... };
// Define Simple
选项 2(Impl
是嵌套 class)
.h 文件
class Simple
{
struct Impl;
...
};
.cpp 文件
// Define Impl
struct Simple::Impl { ... }; // Need the Simple:: scope here.
// Define Simple
和namespace
选项 1(Impl
是同行 class)
.h 文件
namespace weired::example {
struct Impl;
class Simple { ... };
}
.cpp 文件
namespace weired::example {
// Define Impl
struct Impl { ... };
// Define Simple
}
选项 2(Impl
是嵌套 class)
.h 文件
namespace weired::example {
class Simple
{
struct Impl;
...
};
}
.cpp 文件
namespace weired::example {
// Define Impl
struct Simple::Impl { ... }; // Need the Simple:: scope here.
// Define Simple
}