全部
class __declspec(dllexport) MyClass
{
protected:
struct Impl;
Impl *pimpl;
public:
Impl &GetStruct() { return pimpl; }
const std::wstring &GetName() { return pimpl->m_name; };
};
struct MyClass::Impl
{
std::wstring m_name;
};
GetName()引发错误而GetStruct()不会引发错误吗?以及如何修改代码以进行编译?
TIA !!
答案 0 :(得分:2)
问题是C ++解析器从上到下工作。在MyClass
声明的末尾,嵌套Impl
尚未完全定义。它被声明(“有一个Impl结构”),但是完整的定义(“ Impl结构如下……”)仅在以后出现。但是,为了生成pimpl->m_name
的代码,编译器需要了解更多,尤其是需要知道m_name
是什么类型,以及它所在的包含Impl
的偏移量是什么
简而言之,您偶然发现了PIMPL惯用语的一个众所周知的限制,即您不能像以前那样使用内联函数。
答案 1 :(得分:0)
在您请求pimpl->m_name
时,尚不知道m_name
所指向的事物中有一个名为pimpl
的事物。从技术上讲,pimpl
是不完整类型的指针。看到其定义后,它便完成了。
因此,您需要将GetName
的定义移出tye类,并移至MyClass::Impl
的定义之后。
答案 2 :(得分:0)
实际上,我打算将MCVE添加到Ulrichs sufficient answer,但是在尝试使其在coliru上运行时,我发现了更多问题:
MyClass::GetStruct()
的返回类型为Impl&
,但pimpl
之后的return
的类型为Impl*
,这是不兼容的。
MyClass::GetName()
返回const std::string&
,但它本身不是常量。 (我不确定是否允许这样做。我永远不会这样做。)
我添加了一个构造函数/析构函数,因为pimpl
必须使用实例进行初始化。
我删除了副本构造函数和副本分配,因为默认实现会破坏复制pimpl
指针的实例。
我转移了MyClass::GetName()
的实现以解决Ulrich所描述的问题。
固定的示例代码:
#include <iostream>
#include <string>
class MyClass
{
protected:
struct Impl;
Impl *pimpl;
public:
MyClass();
~MyClass();
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
#if 0 // WRONG:
Impl& GetStruct() { return pimpl; }
const std::string &GetName() { return pimpl->m_name; }
#else // BETTER:
Impl& GetStruct() { return *pimpl; }
const std::string& GetName() const;
#endif // 0
};
struct MyClass::Impl
{
std::string m_name;
};
MyClass::MyClass(): pimpl(new Impl()) { }
MyClass::~MyClass() { delete pimpl; }
// Implementation after MyClass::Impl is defined
const std::string& MyClass::GetName() const { return pimpl->m_name; }
int main()
{
MyClass myObj;
std::cout << "myObj.GetName(): '" << myObj.GetName() << "'\n";
return 0;
}
输出:
myObj.GetName(): ''
注意:
我将std::w_string
替换为std::string
,我认为这是无关紧要的更改。 (我没有使用std::w_string
的经验,但我想,如果没有替换,它不会有任何改变。)